1bd26069d391830856c57c2141cd2efbc8423d871Angus Kong/*
2bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * Copyright (C) 2013 The Android Open Source Project
3bd26069d391830856c57c2141cd2efbc8423d871Angus Kong *
4bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * Licensed under the Apache License, Version 2.0 (the "License");
5bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * you may not use this file except in compliance with the License.
6bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * You may obtain a copy of the License at
7bd26069d391830856c57c2141cd2efbc8423d871Angus Kong *
8bd26069d391830856c57c2141cd2efbc8423d871Angus Kong *      http://www.apache.org/licenses/LICENSE-2.0
9bd26069d391830856c57c2141cd2efbc8423d871Angus Kong *
10bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * Unless required by applicable law or agreed to in writing, software
11bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * distributed under the License is distributed on an "AS IS" BASIS,
12bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * See the License for the specific language governing permissions and
14bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * limitations under the License.
15bd26069d391830856c57c2141cd2efbc8423d871Angus Kong */
16bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
17bd26069d391830856c57c2141cd2efbc8423d871Angus Kongpackage com.android.camera.data;
18bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
19b7639c641f2ed5d0c60546349c3aa9e90c026878Sascha Haeberlingimport android.app.Activity;
20bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.content.ContentResolver;
21bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.content.Context;
22bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.database.Cursor;
23bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.graphics.Bitmap;
24bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.graphics.BitmapFactory;
25de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Juddimport android.media.CamcorderProfile;
26bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.net.Uri;
278a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongimport android.os.Bundle;
28bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.provider.MediaStore;
2943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Juddimport android.view.LayoutInflater;
30bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.view.View;
31bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport android.widget.ImageView;
32af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger
33aeed91f3777d08a4160d68ddfc2626808a08b92dSam Juddimport com.android.camera.Storage;
342bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log;
356f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport com.android.camera.util.CameraUtil;
36bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport com.android.camera2.R;
37af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newbergerimport com.bumptech.glide.BitmapRequestBuilder;
384021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Juddimport com.bumptech.glide.Glide;
39af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newbergerimport com.bumptech.glide.load.resource.bitmap.BitmapEncoder;
40bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
41bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport java.io.File;
426f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.text.DateFormat;
43aeed91f3777d08a4160d68ddfc2626808a08b92dSam Juddimport java.util.ArrayList;
44bd26069d391830856c57c2141cd2efbc8423d871Angus Kongimport java.util.Date;
45aeed91f3777d08a4160d68ddfc2626808a08b92dSam Juddimport java.util.List;
46e2fb9943fb2d5a51a651f138d88473bf7f62e0b9Sascha Haeberlingimport java.util.Locale;
47bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
48bd26069d391830856c57c2141cd2efbc8423d871Angus Kong/**
49bd26069d391830856c57c2141cd2efbc8423d871Angus Kong * A base class for all the local media files. The bitmap is loaded in
50b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling * background thread. Subclasses should implement their own background loading
51b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling * thread by sub-classing BitmapLoadTask and overriding doInBackground() to
52b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling * return a bitmap.
53bd26069d391830856c57c2141cd2efbc8423d871Angus Kong */
54bd26069d391830856c57c2141cd2efbc8423d871Angus Kongpublic abstract class LocalMediaData implements LocalData {
55aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    /** The minimum id to use to query for all media at a given media store uri */
56aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    static final int QUERY_ALL_MEDIA_ID = -1;
57aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    private static final String CAMERA_PATH = Storage.DIRECTORY + "%";
58aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    private static final String SELECT_BY_PATH = MediaStore.MediaColumns.DATA + " LIKE ?";
59632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd    private static final int MEDIASTORE_THUMB_WIDTH = 512;
60632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd    private static final int MEDIASTORE_THUMB_HEIGHT = 384;
61aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
623250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong    protected final long mContentId;
63a16e7b50f3148f581439509279f242092e254309ztenghui    protected final String mTitle;
64a16e7b50f3148f581439509279f242092e254309ztenghui    protected final String mMimeType;
65b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers    protected final long mDateTakenInMilliSeconds;
66a16e7b50f3148f581439509279f242092e254309ztenghui    protected final long mDateModifiedInSeconds;
67a16e7b50f3148f581439509279f242092e254309ztenghui    protected final String mPath;
68bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    // width and height should be adjusted according to orientation.
69a16e7b50f3148f581439509279f242092e254309ztenghui    protected final int mWidth;
70a16e7b50f3148f581439509279f242092e254309ztenghui    protected final int mHeight;
71a16e7b50f3148f581439509279f242092e254309ztenghui    protected final long mSizeInBytes;
72a16e7b50f3148f581439509279f242092e254309ztenghui    protected final double mLatitude;
73a16e7b50f3148f581439509279f242092e254309ztenghui    protected final double mLongitude;
748a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    protected final Bundle mMetaData;
75bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
7665ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger    private static final int JPEG_COMPRESS_QUALITY = 90;
7765ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger    private static final BitmapEncoder JPEG_ENCODER =
7865ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger            new BitmapEncoder(Bitmap.CompressFormat.JPEG, JPEG_COMPRESS_QUALITY);
7965ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger
80c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong    /**
81b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling     * Used for thumbnail loading optimization. True if this data has a
82b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling     * corresponding visible view.
83c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong     */
84bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    protected Boolean mUsing = false;
85bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
86280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling    public LocalMediaData(long contentId, String title, String mimeType,
87b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            long dateTakenInMilliSeconds, long dateModifiedInSeconds, String path,
88a16e7b50f3148f581439509279f242092e254309ztenghui            int width, int height, long sizeInBytes, double latitude,
89a16e7b50f3148f581439509279f242092e254309ztenghui            double longitude) {
903250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong        mContentId = contentId;
9143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        mTitle = title;
9243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        mMimeType = mimeType;
93b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers        mDateTakenInMilliSeconds = dateTakenInMilliSeconds;
94a16e7b50f3148f581439509279f242092e254309ztenghui        mDateModifiedInSeconds = dateModifiedInSeconds;
9543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        mPath = path;
96a16e7b50f3148f581439509279f242092e254309ztenghui        mWidth = width;
97a16e7b50f3148f581439509279f242092e254309ztenghui        mHeight = height;
98a16e7b50f3148f581439509279f242092e254309ztenghui        mSizeInBytes = sizeInBytes;
99a16e7b50f3148f581439509279f242092e254309ztenghui        mLatitude = latitude;
100a16e7b50f3148f581439509279f242092e254309ztenghui        mLongitude = longitude;
1018a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        mMetaData = new Bundle();
102a16e7b50f3148f581439509279f242092e254309ztenghui    }
103a16e7b50f3148f581439509279f242092e254309ztenghui
104aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    private interface CursorToLocalData {
105aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        public LocalData build(Cursor cursor);
106aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    }
107aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
108aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    private static List<LocalData> queryLocalMediaData(ContentResolver contentResolver,
109aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            Uri contentUri, String[] projection, long minimumId, String orderBy,
110aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            CursorToLocalData builder) {
111aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        String selection = SELECT_BY_PATH + " AND " + MediaStore.MediaColumns._ID + " > ?";
112aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        String[] selectionArgs = new String[] { CAMERA_PATH, Long.toString(minimumId) };
113aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
114aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        Cursor cursor = contentResolver.query(contentUri, projection,
115aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                selection, selectionArgs, orderBy);
116aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        List<LocalData> result = new ArrayList<LocalData>();
117aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        if (cursor != null) {
118aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            while (cursor.moveToNext()) {
119aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                LocalData data = builder.build(cursor);
120aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                if (data != null) {
121aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                    result.add(data);
122aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                } else {
123aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                    final int dataIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
1242bca210e5fc8a77685775ffb403096167b017dceAngus Kong                    Log.e(TAG, "Error loading data:" + cursor.getString(dataIndex));
125aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                }
126aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            }
127de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd
128de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            cursor.close();
129aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        }
130aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        return result;
131aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    }
132aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
133bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
134bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public long getDateTaken() {
135b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers        return mDateTakenInMilliSeconds;
136bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
137bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
138bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
139bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public long getDateModified() {
140a16e7b50f3148f581439509279f242092e254309ztenghui        return mDateModifiedInSeconds;
141a16e7b50f3148f581439509279f242092e254309ztenghui    }
142a16e7b50f3148f581439509279f242092e254309ztenghui
143a16e7b50f3148f581439509279f242092e254309ztenghui    @Override
1443250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong    public long getContentId() {
1453250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong        return mContentId;
146bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
147bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
148bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
149bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public String getTitle() {
1504021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        return mTitle;
151bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
152bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
153bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
154bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public int getWidth() {
155a16e7b50f3148f581439509279f242092e254309ztenghui        return mWidth;
156bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
157bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
158bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
159bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public int getHeight() {
160a16e7b50f3148f581439509279f242092e254309ztenghui        return mHeight;
161bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
162bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
163bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
164c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong    public int getRotation() {
16587fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu        return 0;
16687fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu    }
16787fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu
16887fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu    @Override
169bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public String getPath() {
170a16e7b50f3148f581439509279f242092e254309ztenghui        return mPath;
171a16e7b50f3148f581439509279f242092e254309ztenghui    }
172a16e7b50f3148f581439509279f242092e254309ztenghui
173a16e7b50f3148f581439509279f242092e254309ztenghui    @Override
174a16e7b50f3148f581439509279f242092e254309ztenghui    public long getSizeInBytes() {
175a16e7b50f3148f581439509279f242092e254309ztenghui        return mSizeInBytes;
176bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
177bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
178bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
179bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public boolean isUIActionSupported(int action) {
180bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        return false;
181bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
182bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
183bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
184bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public boolean isDataActionSupported(int action) {
185bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        return false;
186bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
187bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
188bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
1898a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    public boolean delete(Context context) {
190a16e7b50f3148f581439509279f242092e254309ztenghui        File f = new File(mPath);
191bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        return f.delete();
192bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
193bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
194bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
195bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public void onFullScreen(boolean fullScreen) {
196bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        // do nothing.
197bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
198bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
199bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
200bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public boolean canSwipeInFullScreen() {
201bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        return true;
202bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
203bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
2048a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    protected ImageView fillImageView(Context context, ImageView v,
205632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            int thumbWidth, int thumbHeight, int placeHolderResourceId,
20614ff6c8df2924ccad083591c0fc873322c6828c0Sascha Haeberling            LocalDataAdapter adapter, boolean isInProgress) {
2074021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        Glide.with(context)
208632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds, 0)
209632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            .fitCenter()
210632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            .placeholder(placeHolderResourceId)
211632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            .into(v);
212bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
2131cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger        v.setContentDescription(context.getResources().getString(
2141cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger                R.string.media_date_content_description,
2151cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger                getReadableDate(mDateModifiedInSeconds)));
216a293597032795e3f245e9f0d5b20701375904e04Alan Newberger
217bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        return v;
218bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
219bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
220bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
221632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd    public View getView(Context context, View recycled, int thumbWidth, int thumbHeight,
2224021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgress) {
22343bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        final ImageView imageView;
22443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        if (recycled != null) {
22543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            imageView = (ImageView) recycled;
22643bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        } else {
227919bea1a10464f23aeb090a254ff36169d012e9aSpike Sprague            imageView = (ImageView) LayoutInflater.from(context)
228919bea1a10464f23aeb090a254ff36169d012e9aSpike Sprague                .inflate(R.layout.filmstrip_image, null);
229a93ba0dbd8e4000f3643567809a4a3fac554fd3cSpike Sprague            imageView.setTag(R.id.mediadata_tag_viewtype, getItemViewType().ordinal());
23043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        }
23143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd
232632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd        return fillImageView(context, imageView, thumbWidth, thumbHeight,
2334021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd                placeHolderResourceId, adapter, isInProgress);
234bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
235bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
236bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
237632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd    public void loadFullImage(Context context, int thumbWidth, int thumbHeight, View view,
2384021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            LocalDataAdapter adapter) {
239caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        // Default is do nothing.
240caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        // Can be implemented by sub-classes.
241caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers    }
242caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers
243caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers    @Override
244bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    public void prepare() {
245bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        synchronized (mUsing) {
246bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            mUsing = true;
247bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
248bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
249bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
250bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
2514021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd    public void recycle(View view) {
252bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        synchronized (mUsing) {
253bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            mUsing = false;
254bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
255bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
256bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
257fae11a165e344a38811770c7d348eda214683edcSascha Haeberling    @Override
258fae11a165e344a38811770c7d348eda214683edcSascha Haeberling    public double[] getLatLong() {
259a16e7b50f3148f581439509279f242092e254309ztenghui        if (mLatitude == 0 && mLongitude == 0) {
260fae11a165e344a38811770c7d348eda214683edcSascha Haeberling            return null;
261fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        }
262fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        return new double[] {
263a16e7b50f3148f581439509279f242092e254309ztenghui                mLatitude, mLongitude
264fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        };
265fae11a165e344a38811770c7d348eda214683edcSascha Haeberling    }
266fae11a165e344a38811770c7d348eda214683edcSascha Haeberling
267bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    protected boolean isUsing() {
268bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        synchronized (mUsing) {
269bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return mUsing;
270bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
271bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
272bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
273bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    @Override
27488ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling    public String getMimeType() {
275a16e7b50f3148f581439509279f242092e254309ztenghui        return mMimeType;
27688ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling    }
27788ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling
27888ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling    @Override
279b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling    public MediaDetails getMediaDetails(Context context) {
280b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        MediaDetails mediaDetails = new MediaDetails();
281a16e7b50f3148f581439509279f242092e254309ztenghui        mediaDetails.addDetail(MediaDetails.INDEX_TITLE, mTitle);
282a16e7b50f3148f581439509279f242092e254309ztenghui        mediaDetails.addDetail(MediaDetails.INDEX_WIDTH, mWidth);
283a16e7b50f3148f581439509279f242092e254309ztenghui        mediaDetails.addDetail(MediaDetails.INDEX_HEIGHT, mHeight);
284a16e7b50f3148f581439509279f242092e254309ztenghui        mediaDetails.addDetail(MediaDetails.INDEX_PATH, mPath);
285b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        mediaDetails.addDetail(MediaDetails.INDEX_DATETIME,
2861cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger                getReadableDate(mDateModifiedInSeconds));
287a16e7b50f3148f581439509279f242092e254309ztenghui        if (mSizeInBytes > 0) {
288a16e7b50f3148f581439509279f242092e254309ztenghui            mediaDetails.addDetail(MediaDetails.INDEX_SIZE, mSizeInBytes);
289b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        }
290a16e7b50f3148f581439509279f242092e254309ztenghui        if (mLatitude != 0 && mLongitude != 0) {
291a16e7b50f3148f581439509279f242092e254309ztenghui            String locationString = String.format(Locale.getDefault(), "%f, %f", mLatitude,
292a16e7b50f3148f581439509279f242092e254309ztenghui                    mLongitude);
293e2fb9943fb2d5a51a651f138d88473bf7f62e0b9Sascha Haeberling            mediaDetails.addDetail(MediaDetails.INDEX_LOCATION, locationString);
294b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        }
295b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        return mediaDetails;
296b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling    }
297b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling
298ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague    private static String getReadableDate(long dateInSeconds) {
2991cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger        DateFormat dateFormatter = DateFormat.getDateTimeInstance();
3001cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger        return dateFormatter.format(new Date(dateInSeconds * 1000));
3011cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger    }
3021cfa3dd77d3828985d37beffbfad9388af054757Alan Newberger
303b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling    @Override
304c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong    public abstract int getViewType();
305bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
3068a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    @Override
3078a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    public Bundle getMetadata() {
3088a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        return mMetaData;
3098a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong    }
3108a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong
31156102c6a83104cea1371114d77a57e1934f2c648Angus Kong    @Override
31256102c6a83104cea1371114d77a57e1934f2c648Angus Kong    public boolean isMetadataUpdated() {
313de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        return MetadataLoader.isMetadataCached(this);
31456102c6a83104cea1371114d77a57e1934f2c648Angus Kong    }
31556102c6a83104cea1371114d77a57e1934f2c648Angus Kong
316a16e7b50f3148f581439509279f242092e254309ztenghui    public static final class PhotoData extends LocalMediaData {
3172bca210e5fc8a77685775ffb403096167b017dceAngus Kong        private static final Log.Tag TAG = new Log.Tag("PhotoData");
318bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
319bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_ID = 0;
320bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_TITLE = 1;
321bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_MIME_TYPE = 2;
322bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATE_TAKEN = 3;
323bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATE_MODIFIED = 4;
324bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATA = 5;
325bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_ORIENTATION = 6;
326bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_WIDTH = 7;
327bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_HEIGHT = 8;
3286f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        public static final int COL_SIZE = 9;
329fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        public static final int COL_LATITUDE = 10;
330fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        public static final int COL_LONGITUDE = 11;
331bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
332caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        // GL max texture size: keep bitmaps below this value.
333caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        private static final int MAXIMUM_TEXTURE_SIZE = 2048;
334caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers
335bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        static final Uri CONTENT_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
336bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
337aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static final String QUERY_ORDER = MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC, "
338bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                + MediaStore.Images.ImageColumns._ID + " DESC";
339bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        /**
340bd26069d391830856c57c2141cd2efbc8423d871Angus Kong         * These values should be kept in sync with column IDs (COL_*) above.
341bd26069d391830856c57c2141cd2efbc8423d871Angus Kong         */
342aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static final String[] QUERY_PROJECTION = {
343b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns._ID,           // 0, int
344b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.TITLE,         // 1, string
345b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.MIME_TYPE,     // 2, string
346b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.DATE_TAKEN,    // 3, int
347b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.DATE_MODIFIED, // 4, int
348b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.DATA,          // 5, string
349b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.ORIENTATION,   // 6, int, 0, 90, 180, 270
350b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.WIDTH,         // 7, int
351b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.HEIGHT,        // 8, int
352b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.SIZE,          // 9, long
353b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.LATITUDE,      // 10, double
354b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Images.ImageColumns.LONGITUDE      // 11, double
355bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        };
356bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
357e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        private static final int mSupportedUIActions = ACTION_DEMOTE | ACTION_PROMOTE | ACTION_ZOOM;
358bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        private static final int mSupportedDataActions =
359e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong                DATA_ACTION_DELETE | DATA_ACTION_EDIT | DATA_ACTION_SHARE;
360bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
361bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        /** from MediaStore, can only be 0, 90, 180, 270 */
362a16e7b50f3148f581439509279f242092e254309ztenghui        private final int mOrientation;
3634021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        /** @see #getSignature() */
3644021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        private final String mSignature;
365a16e7b50f3148f581439509279f242092e254309ztenghui
366571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        public static LocalData fromContentUri(ContentResolver cr, Uri contentUri) {
367571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            List<LocalData> newPhotos = query(cr, contentUri, QUERY_ALL_MEDIA_ID);
368571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            if (newPhotos.isEmpty()) {
369571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong                return null;
370571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            }
371571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            return newPhotos.get(0);
372571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        }
373571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong
374a16e7b50f3148f581439509279f242092e254309ztenghui        public PhotoData(long id, String title, String mimeType,
375b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers                long dateTakenInMilliSeconds, long dateModifiedInSeconds,
376a16e7b50f3148f581439509279f242092e254309ztenghui                String path, int orientation, int width, int height,
377a16e7b50f3148f581439509279f242092e254309ztenghui                long sizeInBytes, double latitude, double longitude) {
378b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            super(id, title, mimeType, dateTakenInMilliSeconds, dateModifiedInSeconds,
379a16e7b50f3148f581439509279f242092e254309ztenghui                    path, width, height, sizeInBytes, latitude, longitude);
380a16e7b50f3148f581439509279f242092e254309ztenghui            mOrientation = orientation;
3814021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            mSignature = mimeType + orientation + dateModifiedInSeconds;
382a16e7b50f3148f581439509279f242092e254309ztenghui        }
383bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
384aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        static List<LocalData> query(ContentResolver cr, Uri uri, long lastId) {
385aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            return queryLocalMediaData(cr, uri, QUERY_PROJECTION, lastId, QUERY_ORDER,
386aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                    new PhotoDataBuilder());
387aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        }
388aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
389aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static PhotoData buildFromCursor(Cursor c) {
390a16e7b50f3148f581439509279f242092e254309ztenghui            long id = c.getLong(COL_ID);
391a16e7b50f3148f581439509279f242092e254309ztenghui            String title = c.getString(COL_TITLE);
392a16e7b50f3148f581439509279f242092e254309ztenghui            String mimeType = c.getString(COL_MIME_TYPE);
393b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            long dateTakenInMilliSeconds = c.getLong(COL_DATE_TAKEN);
394a16e7b50f3148f581439509279f242092e254309ztenghui            long dateModifiedInSeconds = c.getLong(COL_DATE_MODIFIED);
395a16e7b50f3148f581439509279f242092e254309ztenghui            String path = c.getString(COL_DATA);
396a16e7b50f3148f581439509279f242092e254309ztenghui            int orientation = c.getInt(COL_ORIENTATION);
397a16e7b50f3148f581439509279f242092e254309ztenghui            int width = c.getInt(COL_WIDTH);
398a16e7b50f3148f581439509279f242092e254309ztenghui            int height = c.getInt(COL_HEIGHT);
399a16e7b50f3148f581439509279f242092e254309ztenghui            if (width <= 0 || height <= 0) {
40062a622b22717b454d3de26bb3311536a27492b6eAngus Kong                Log.w(TAG, "Zero dimension in ContentResolver for "
401a16e7b50f3148f581439509279f242092e254309ztenghui                        + path + ":" + width + "x" + height);
402bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                BitmapFactory.Options opts = new BitmapFactory.Options();
403bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                opts.inJustDecodeBounds = true;
404a16e7b50f3148f581439509279f242092e254309ztenghui                BitmapFactory.decodeFile(path, opts);
40562a622b22717b454d3de26bb3311536a27492b6eAngus Kong                if (opts.outWidth > 0 && opts.outHeight > 0) {
406a16e7b50f3148f581439509279f242092e254309ztenghui                    width = opts.outWidth;
407a16e7b50f3148f581439509279f242092e254309ztenghui                    height = opts.outHeight;
408bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                } else {
40962a622b22717b454d3de26bb3311536a27492b6eAngus Kong                    Log.w(TAG, "Dimension decode failed for " + path);
410a16e7b50f3148f581439509279f242092e254309ztenghui                    Bitmap b = BitmapFactory.decodeFile(path);
411bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                    if (b == null) {
4123250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong                        Log.w(TAG, "PhotoData skipped."
41362a622b22717b454d3de26bb3311536a27492b6eAngus Kong                                + " Decoding " + path + "failed.");
414bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                        return null;
415bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                    }
416a16e7b50f3148f581439509279f242092e254309ztenghui                    width = b.getWidth();
417a16e7b50f3148f581439509279f242092e254309ztenghui                    height = b.getHeight();
41862a622b22717b454d3de26bb3311536a27492b6eAngus Kong                    if (width == 0 || height == 0) {
41962a622b22717b454d3de26bb3311536a27492b6eAngus Kong                        Log.w(TAG, "PhotoData skipped. Bitmap size 0 for " + path);
42062a622b22717b454d3de26bb3311536a27492b6eAngus Kong                        return null;
42162a622b22717b454d3de26bb3311536a27492b6eAngus Kong                    }
422bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                }
423bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            }
42406578b59bf15c1ac35dbbffd979f40479b1cbda9ztenghui
425a16e7b50f3148f581439509279f242092e254309ztenghui            long sizeInBytes = c.getLong(COL_SIZE);
426a16e7b50f3148f581439509279f242092e254309ztenghui            double latitude = c.getDouble(COL_LATITUDE);
427a16e7b50f3148f581439509279f242092e254309ztenghui            double longitude = c.getDouble(COL_LONGITUDE);
428b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            PhotoData result = new PhotoData(id, title, mimeType, dateTakenInMilliSeconds,
429a16e7b50f3148f581439509279f242092e254309ztenghui                    dateModifiedInSeconds, path, orientation, width, height,
430a16e7b50f3148f581439509279f242092e254309ztenghui                    sizeInBytes, latitude, longitude);
431a16e7b50f3148f581439509279f242092e254309ztenghui            return result;
432a16e7b50f3148f581439509279f242092e254309ztenghui        }
433a16e7b50f3148f581439509279f242092e254309ztenghui
43487fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu        @Override
435c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong        public int getRotation() {
436a16e7b50f3148f581439509279f242092e254309ztenghui            return mOrientation;
437bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
438bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
439bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
440bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public String toString() {
441a16e7b50f3148f581439509279f242092e254309ztenghui            return "Photo:" + ",data=" + mPath + ",mimeType=" + mMimeType
442a16e7b50f3148f581439509279f242092e254309ztenghui                    + "," + mWidth + "x" + mHeight + ",orientation=" + mOrientation
443b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers                    + ",date=" + new Date(mDateTakenInMilliSeconds);
444bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
445bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
446bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
447c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        public int getViewType() {
448b21215a1a59812592380f31891becedbdec7468bAngus Kong            return VIEW_TYPE_REMOVABLE;
449bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
450bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
451bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
452bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public boolean isUIActionSupported(int action) {
453bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return ((action & mSupportedUIActions) == action);
454bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
455bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
456bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
457bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public boolean isDataActionSupported(int action) {
458bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return ((action & mSupportedDataActions) == action);
459bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
460bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
461bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
4628a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        public boolean delete(Context context) {
4638a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong            ContentResolver cr = context.getContentResolver();
4643250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong            cr.delete(CONTENT_URI, MediaStore.Images.ImageColumns._ID + "=" + mContentId, null);
4658a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong            return super.delete(context);
466bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
467bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
468bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
469571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        public Uri getUri() {
470bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            Uri baseUri = CONTENT_URI;
4713250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong            return baseUri.buildUpon().appendPath(String.valueOf(mContentId)).build();
472bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
473bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
474bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
4756f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        public MediaDetails getMediaDetails(Context context) {
476b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling            MediaDetails mediaDetails = super.getMediaDetails(context);
477a16e7b50f3148f581439509279f242092e254309ztenghui            MediaDetails.extractExifInfo(mediaDetails, mPath);
478bfd919aff7007f5dc26c74dfb97705c8e23e09b8Sascha Haeberling            mediaDetails.addDetail(MediaDetails.INDEX_ORIENTATION, mOrientation);
4796f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling            return mediaDetails;
4806f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        }
4816f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling
4826f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        @Override
483fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        public int getLocalDataType() {
484c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong            return LOCAL_IMAGE;
485c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        }
486c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong
487c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        @Override
4888a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        public LocalData refresh(Context context) {
489aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            PhotoData newData = null;
490571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            Cursor c = context.getContentResolver().query(getUri(), QUERY_PROJECTION, null,
4918a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong                    null, null);
492aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            if (c != null) {
493aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                if (c.moveToFirst()) {
494aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                    newData = buildFromCursor(c);
495aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                }
496aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                c.close();
497bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            }
498aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
499a16e7b50f3148f581439509279f242092e254309ztenghui            return newData;
500bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
501bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
502bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
5034021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public String getSignature() {
5044021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return mSignature;
50543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        }
50643bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd
50743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        @Override
508632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd        protected ImageView fillImageView(Context context, final ImageView v, final int thumbWidth,
509632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                final int thumbHeight, int placeHolderResourceId, LocalDataAdapter adapter,
5104021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd                boolean isInProgress) {
511632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            loadImage(context, v, thumbWidth, thumbHeight, placeHolderResourceId, false);
512ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague
513159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            int stringId = R.string.photo_date_content_description;
514159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            if (PanoramaMetadataLoader.isPanorama(this) ||
515159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                PanoramaMetadataLoader.isPanorama360(this)) {
516159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                stringId = R.string.panorama_date_content_description;
517159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            } else if (PanoramaMetadataLoader.isPanoramaAndUseViewer(this)) {
518159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                // assume it's a PhotoSphere
519159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                stringId = R.string.photosphere_date_content_description;
520159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            } else if (RgbzMetadataLoader.hasRGBZData(this)) {
521159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                stringId = R.string.refocus_date_content_description;
522159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            }
523159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague
524ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague            v.setContentDescription(context.getResources().getString(
525159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                    stringId,
526ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague                    getReadableDate(mDateModifiedInSeconds)));
527ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague
5284021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return v;
5294021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        }
5304021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd
531632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd        private void loadImage(Context context, ImageView imageView, int thumbWidth,
532632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                int thumbHeight, int placeHolderResourceId, boolean full) {
5334021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd
534acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            //TODO: Figure out why these can be <= 0.
535acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            if (thumbWidth <= 0 || thumbHeight <=0) {
536acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd                return;
537acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            }
538acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd
539af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger            BitmapRequestBuilder<Uri, Bitmap> request = Glide.with(context)
540632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds, mOrientation)
541af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                .asBitmap()
542af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                .encoder(JPEG_ENCODER)
543632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .placeholder(placeHolderResourceId)
544632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .fitCenter();
545632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            if (full) {
546632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                request.thumbnail(Glide.with(context)
547632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds,
548632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                            mOrientation)
549af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                        .asBitmap()
550af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                        .encoder(JPEG_ENCODER)
551632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        .override(thumbWidth, thumbHeight)
552632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        .fitCenter())
553632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                    .override(Math.min(getWidth(), MAXIMUM_TEXTURE_SIZE),
554632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        Math.min(getHeight(), MAXIMUM_TEXTURE_SIZE));
555632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            } else {
556632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                request.thumbnail(Glide.with(context)
557632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds,
558632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                            mOrientation)
559af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                        .asBitmap()
560af79e4288559ddbee4ba6ed3cb3d1d9657fc23eaAlan Newberger                        .encoder(JPEG_ENCODER)
561632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                        .override(MEDIASTORE_THUMB_WIDTH, MEDIASTORE_THUMB_HEIGHT))
562632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                    .override(thumbWidth, thumbHeight);
563632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            }
564632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            request.into(imageView);
565caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        }
5665850115399516c9186cc0a8231eb1b554f570441Sascha Haeberling
567caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers        @Override
5684021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public void recycle(View view) {
5694021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            super.recycle(view);
5704021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            if (view != null) {
571632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                Glide.clear(view);
5724021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            }
573bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
574bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
575aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        @Override
5764021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public LocalDataViewType getItemViewType() {
5774021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return LocalDataViewType.PHOTO;
578aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        }
579aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
5804021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        @Override
581632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd        public void loadFullImage(Context context, int thumbWidth, int thumbHeight, View v,
582632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            LocalDataAdapter adapter)
5834021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        {
584632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            loadImage(context, (ImageView) v, thumbWidth, thumbHeight, 0, true);
5854021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        }
586b7be228d192cb8f91079caaa2f77a884a40b1160ztenghui
5874021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        private static class PhotoDataBuilder implements CursorToLocalData {
5884021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            @Override
5894021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            public PhotoData build(Cursor cursor) {
5904021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd                return LocalMediaData.PhotoData.buildFromCursor(cursor);
591bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            }
5924021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        }
593bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
594bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
595a16e7b50f3148f581439509279f242092e254309ztenghui    public static final class VideoData extends LocalMediaData {
596bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_ID = 0;
597bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_TITLE = 1;
598bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_MIME_TYPE = 2;
599bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATE_TAKEN = 3;
600bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATE_MODIFIED = 4;
601bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_DATA = 5;
602bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_WIDTH = 6;
603bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public static final int COL_HEIGHT = 7;
60443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public static final int COL_SIZE = 8;
60543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public static final int COL_LATITUDE = 9;
60643bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public static final int COL_LONGITUDE = 10;
60743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public static final int COL_DURATION = 11;
608bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
609bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        static final Uri CONTENT_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
610bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
611e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        private static final int mSupportedUIActions = ACTION_DEMOTE | ACTION_PROMOTE;
612bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        private static final int mSupportedDataActions =
613e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong                DATA_ACTION_DELETE | DATA_ACTION_PLAY | DATA_ACTION_SHARE;
614bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
615aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static final String QUERY_ORDER = MediaStore.Video.VideoColumns.DATE_TAKEN
616aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd                + " DESC, " + MediaStore.Video.VideoColumns._ID + " DESC";
617bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        /**
618bd26069d391830856c57c2141cd2efbc8423d871Angus Kong         * These values should be kept in sync with column IDs (COL_*) above.
619bd26069d391830856c57c2141cd2efbc8423d871Angus Kong         */
620aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static final String[] QUERY_PROJECTION = {
621b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns._ID,           // 0, int
622b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.TITLE,         // 1, string
623b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.MIME_TYPE,     // 2, string
624b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.DATE_TAKEN,    // 3, int
625b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.DATE_MODIFIED, // 4, int
626b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.DATA,          // 5, string
627b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.WIDTH,         // 6, int
628b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling                MediaStore.Video.VideoColumns.HEIGHT,        // 7, int
62943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                MediaStore.Video.VideoColumns.SIZE,          // 8 long
63043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                MediaStore.Video.VideoColumns.LATITUDE,      // 9 double
63143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                MediaStore.Video.VideoColumns.LONGITUDE,     // 10 double
63243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                MediaStore.Video.VideoColumns.DURATION       // 11 long
633bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        };
634bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
635b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling        /** The duration in milliseconds. */
636280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling        private final long mDurationInSeconds;
6374021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        private final String mSignature;
638a16e7b50f3148f581439509279f242092e254309ztenghui
639a16e7b50f3148f581439509279f242092e254309ztenghui        public VideoData(long id, String title, String mimeType,
640b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers                long dateTakenInMilliSeconds, long dateModifiedInSeconds,
641a16e7b50f3148f581439509279f242092e254309ztenghui                String path, int width, int height, long sizeInBytes,
642a16e7b50f3148f581439509279f242092e254309ztenghui                double latitude, double longitude, long durationInSeconds) {
643b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            super(id, title, mimeType, dateTakenInMilliSeconds, dateModifiedInSeconds,
644a16e7b50f3148f581439509279f242092e254309ztenghui                    path, width, height, sizeInBytes, latitude, longitude);
645a16e7b50f3148f581439509279f242092e254309ztenghui            mDurationInSeconds = durationInSeconds;
6464021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            mSignature = mimeType + dateModifiedInSeconds;
647a16e7b50f3148f581439509279f242092e254309ztenghui        }
648b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling
649571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        public static LocalData fromContentUri(ContentResolver cr, Uri contentUri) {
650571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            List<LocalData> newVideos = query(cr, contentUri, QUERY_ALL_MEDIA_ID);
651571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            if (newVideos.isEmpty()) {
652571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong                return null;
653571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            }
654571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            return newVideos.get(0);
655571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        }
656571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong
657571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        static List<LocalData> query(ContentResolver cr, Uri uri, long lastId) {
658571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            return queryLocalMediaData(cr, uri, QUERY_PROJECTION, lastId, QUERY_ORDER,
659571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong                    new VideoDataBuilder());
660aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        }
661aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
662de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        /**
663de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * We can't trust the media store and we can't afford the performance overhead of
664de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * synchronously decoding the video header for every item when loading our data set
665de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * from the media store, so we instead run the metadata loader in the background
666de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * to decode the video header for each item and prefer whatever values it obtains.
667de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         */
668de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        private int getBestWidth() {
669de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            int metadataWidth = VideoRotationMetadataLoader.getWidth(this);
670de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            if (metadataWidth > 0) {
671de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                return metadataWidth;
672de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            } else {
673de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                return mWidth;
674de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            }
675de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        }
676de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd
677de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        private int getBestHeight() {
678de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            int metadataHeight = VideoRotationMetadataLoader.getHeight(this);
679de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            if (metadataHeight > 0) {
680de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                return metadataHeight;
681de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            } else {
682de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                return mHeight;
683de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            }
684de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        }
685de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd
686de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        /**
687de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * If the metadata loader has determined from the video header that we need to rotate the video
688de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         * 90 or 270 degrees, then we swap the width and height.
689de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd         */
690de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        @Override
691de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        public int getWidth() {
692de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            return VideoRotationMetadataLoader.isRotated(this) ? getBestHeight() : getBestWidth();
693de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        }
694de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd
695de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        @Override
696de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        public int getHeight() {
697de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            return VideoRotationMetadataLoader.isRotated(this) ?  getBestWidth() : getBestHeight();
698de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        }
699de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd
700aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        private static VideoData buildFromCursor(Cursor c) {
701a16e7b50f3148f581439509279f242092e254309ztenghui            long id = c.getLong(COL_ID);
702a16e7b50f3148f581439509279f242092e254309ztenghui            String title = c.getString(COL_TITLE);
703a16e7b50f3148f581439509279f242092e254309ztenghui            String mimeType = c.getString(COL_MIME_TYPE);
704b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            long dateTakenInMilliSeconds = c.getLong(COL_DATE_TAKEN);
705a16e7b50f3148f581439509279f242092e254309ztenghui            long dateModifiedInSeconds = c.getLong(COL_DATE_MODIFIED);
706a16e7b50f3148f581439509279f242092e254309ztenghui            String path = c.getString(COL_DATA);
707a16e7b50f3148f581439509279f242092e254309ztenghui            int width = c.getInt(COL_WIDTH);
708a16e7b50f3148f581439509279f242092e254309ztenghui            int height = c.getInt(COL_HEIGHT);
709a16e7b50f3148f581439509279f242092e254309ztenghui
710de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            // If the media store doesn't contain a width and a height, use the width and height
711de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            // of the default camera mode instead. When the metadata loader runs, it will set the
712de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd            // correct values.
713a16e7b50f3148f581439509279f242092e254309ztenghui            if (width == 0 || height == 0) {
714de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                Log.w(TAG, "failed to retrieve width and height from the media store, defaulting " +
715de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                        " to camera profile");
716de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
717de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                width = profile.videoFrameWidth;
718de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd                height = profile.videoFrameHeight;
719bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            }
720b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling
721a16e7b50f3148f581439509279f242092e254309ztenghui            long sizeInBytes = c.getLong(COL_SIZE);
722a16e7b50f3148f581439509279f242092e254309ztenghui            double latitude = c.getDouble(COL_LATITUDE);
723a16e7b50f3148f581439509279f242092e254309ztenghui            double longitude = c.getDouble(COL_LONGITUDE);
724a16e7b50f3148f581439509279f242092e254309ztenghui            long durationInSeconds = c.getLong(COL_DURATION) / 1000;
725b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers            VideoData d = new VideoData(id, title, mimeType, dateTakenInMilliSeconds,
726a16e7b50f3148f581439509279f242092e254309ztenghui                    dateModifiedInSeconds, path, width, height, sizeInBytes,
727a16e7b50f3148f581439509279f242092e254309ztenghui                    latitude, longitude, durationInSeconds);
728bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return d;
729bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
730bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
731bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
732bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public String toString() {
733a16e7b50f3148f581439509279f242092e254309ztenghui            return "Video:" + ",data=" + mPath + ",mimeType=" + mMimeType
734b8600b2b798f6b28e405380a17bd5f6fc23fcc82Andy Huibers                    + "," + mWidth + "x" + mHeight + ",date=" + new Date(mDateTakenInMilliSeconds);
735bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
736bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
737bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
738c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        public int getViewType() {
739b21215a1a59812592380f31891becedbdec7468bAngus Kong            return VIEW_TYPE_REMOVABLE;
740bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
741bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
742bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
743bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public boolean isUIActionSupported(int action) {
744bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return ((action & mSupportedUIActions) == action);
745bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
746bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
747bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
748bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        public boolean isDataActionSupported(int action) {
749bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            return ((action & mSupportedDataActions) == action);
750bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
751bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
752bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
7538a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        public boolean delete(Context context) {
7548a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong            ContentResolver cr = context.getContentResolver();
7553250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong            cr.delete(CONTENT_URI, MediaStore.Video.VideoColumns._ID + "=" + mContentId, null);
7568a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong            return super.delete(context);
757bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
758bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
759bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
760571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong        public Uri getUri() {
761bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            Uri baseUri = CONTENT_URI;
7623250987bd014d1c5463b8a39bbe988165ab1cc3fAngus Kong            return baseUri.buildUpon().appendPath(String.valueOf(mContentId)).build();
763bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
764c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong
765c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        @Override
7666f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        public MediaDetails getMediaDetails(Context context) {
767b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling            MediaDetails mediaDetails = super.getMediaDetails(context);
768a16e7b50f3148f581439509279f242092e254309ztenghui            String duration = MediaDetails.formatDuration(context, mDurationInSeconds);
769b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling            mediaDetails.addDetail(MediaDetails.INDEX_DURATION, duration);
770b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling            return mediaDetails;
7716f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        }
7726f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling
7736f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling        @Override
774fae11a165e344a38811770c7d348eda214683edcSascha Haeberling        public int getLocalDataType() {
775c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong            return LOCAL_VIDEO;
776c27d21bc3b9322936004827ab005fb7d1facfacfAngus Kong        }
777bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
778bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
7798a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong        public LocalData refresh(Context context) {
780571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong            Cursor c = context.getContentResolver().query(getUri(), QUERY_PROJECTION, null,
7818a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong                    null, null);
782b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling            if (c == null || !c.moveToFirst()) {
783a16e7b50f3148f581439509279f242092e254309ztenghui                return null;
784bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            }
785bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            VideoData newData = buildFromCursor(c);
786a16e7b50f3148f581439509279f242092e254309ztenghui            return newData;
787bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
788bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
789bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
7904021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public String getSignature() {
7914021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return mSignature;
7924021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        }
7934021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd
7944021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        @Override
795632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd        protected ImageView fillImageView(Context context, final ImageView v, final int thumbWidth,
796632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                final int thumbHeight, int placeHolderResourceId, LocalDataAdapter adapter,
7974021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd                boolean isInProgress) {
798acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd
799acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            //TODO: Figure out why these can be <= 0.
800acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            if (thumbWidth <= 0 || thumbHeight <=0) {
801acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd                return v;
802acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd            }
803acfad92c88807c99cf5165b201f24b9d76a8cdf4Sam Judd
8044021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            Glide.with(context)
805632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds, 0)
80665ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger                .asBitmap()
80765ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger                .encoder(JPEG_ENCODER)
808632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .thumbnail(Glide.with(context)
809632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                    .loadFromMediaStore(getUri(), mMimeType, mDateModifiedInSeconds, 0)
81065ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger                    .asBitmap()
81165ab02000f65a8677adf9fab5c296e0d3ef64cbcAlan Newberger                    .encoder(JPEG_ENCODER)
812632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                    .override(MEDIASTORE_THUMB_WIDTH, MEDIASTORE_THUMB_HEIGHT))
813632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .placeholder(placeHolderResourceId)
814632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .fitCenter()
815632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .override(thumbWidth, thumbHeight)
816632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                .into(v);
8174021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd
818159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            // Content descriptions applied to parent FrameView
819159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            // see getView
820ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague
8214021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return v;
8224021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        }
8234021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd
8244021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        @Override
82543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public View getView(final Context context, View recycled,
826632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd                int thumbWidth, int thumbHeight, int placeHolderResourceId,
82714ff6c8df2924ccad083591c0fc873322c6828c0Sascha Haeberling                LocalDataAdapter adapter, boolean isInProgress) {
828bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
82943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            final VideoViewHolder viewHolder;
83043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            final View result;
83143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            if (recycled != null) {
83243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                result = recycled;
833bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague                viewHolder = (VideoViewHolder) recycled.getTag(R.id.mediadata_tag_target);
83443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            } else {
83543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                result = LayoutInflater.from(context).inflate(R.layout.filmstrip_video, null);
836a93ba0dbd8e4000f3643567809a4a3fac554fd3cSpike Sprague                result.setTag(R.id.mediadata_tag_viewtype, getItemViewType().ordinal());
83743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                ImageView videoView = (ImageView) result.findViewById(R.id.video_view);
83843bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                ImageView playButton = (ImageView) result.findViewById(R.id.play_button);
83943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd                viewHolder = new VideoViewHolder(videoView, playButton);
840bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague                result.setTag(R.id.mediadata_tag_target, viewHolder);
84143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            }
84243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd
843632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            fillImageView(context, viewHolder.mVideoView, thumbWidth, thumbHeight,
8444021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd                    placeHolderResourceId, adapter, isInProgress);
845bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
846bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            // ImageView for the play icon.
84743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            viewHolder.mPlayButton.setOnClickListener(new View.OnClickListener() {
848bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                @Override
849bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                public void onClick(View v) {
850280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling                    // TODO: refactor this into activities to avoid this class
851280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling                    // conversion.
852571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong                    CameraUtil.playVideo((Activity) context, getUri(), mTitle);
853bd26069d391830856c57c2141cd2efbc8423d871Angus Kong                }
854bd26069d391830856c57c2141cd2efbc8423d871Angus Kong            });
855bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
856159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague            result.setContentDescription(context.getResources().getString(
857159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                    R.string.video_date_content_description,
858159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague                    getReadableDate(mDateModifiedInSeconds)));
859159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague
86043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            return result;
86143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        }
86243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd
86343bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        @Override
8644021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public void recycle(View view) {
8654021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            super.recycle(view);
866bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague            VideoViewHolder videoViewHolder =
867bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague                    (VideoViewHolder) view.getTag(R.id.mediadata_tag_target);
868632eaafda53eb59b15c81ddeaf2080e6d8515f59Sam Judd            Glide.clear(videoViewHolder.mVideoView);
869bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
870bd26069d391830856c57c2141cd2efbc8423d871Angus Kong
871bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        @Override
8724021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd        public LocalDataViewType getItemViewType() {
8734021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd            return LocalDataViewType.VIDEO;
874bd26069d391830856c57c2141cd2efbc8423d871Angus Kong        }
875bd26069d391830856c57c2141cd2efbc8423d871Angus Kong    }
876caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers
877aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    private static class VideoDataBuilder implements CursorToLocalData {
878aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
879aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        @Override
880aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        public VideoData build(Cursor cursor) {
881aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd            return LocalMediaData.VideoData.buildFromCursor(cursor);
882aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd        }
883aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd    }
884aeed91f3777d08a4160d68ddfc2626808a08b92dSam Judd
88543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd     private static class VideoViewHolder {
88643bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        private final ImageView mVideoView;
88743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        private final ImageView mPlayButton;
88843bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd
88943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        public VideoViewHolder(ImageView videoView, ImageView playButton) {
89043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            mVideoView = videoView;
89143bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd            mPlayButton = playButton;
89243bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd        }
89343bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd    }
894bd26069d391830856c57c2141cd2efbc8423d871Angus Kong}
895