1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.photos.shims;
18
19import android.content.AsyncTaskLoader;
20import android.content.Context;
21import android.database.Cursor;
22import android.database.MatrixCursor;
23import android.graphics.drawable.Drawable;
24import android.net.Uri;
25
26import com.android.gallery3d.data.ContentListener;
27import com.android.gallery3d.data.DataManager;
28import com.android.gallery3d.data.MediaItem;
29import com.android.gallery3d.data.MediaObject;
30import com.android.gallery3d.data.MediaSet;
31import com.android.gallery3d.data.Path;
32import com.android.gallery3d.data.MediaSet.SyncListener;
33import com.android.gallery3d.util.Future;
34import com.android.photos.data.AlbumSetLoader;
35
36import java.util.ArrayList;
37
38/**
39 * Returns all MediaSets in a MediaSet, wrapping them in a cursor to appear
40 * like a AlbumSetLoader.
41 */
42public class MediaSetLoader extends AsyncTaskLoader<Cursor> implements LoaderCompatShim<Cursor>{
43
44    private static final SyncListener sNullListener = new SyncListener() {
45        @Override
46        public void onSyncDone(MediaSet mediaSet, int resultCode) {
47        }
48    };
49
50    private final MediaSet mMediaSet;
51    private final DataManager mDataManager;
52    private Future<Integer> mSyncTask = null;
53    private ContentListener mObserver = new ContentListener() {
54        @Override
55        public void onContentDirty() {
56            onContentChanged();
57        }
58    };
59
60    private ArrayList<MediaItem> mCoverItems;
61
62    public MediaSetLoader(Context context) {
63        super(context);
64        mDataManager = DataManager.from(context);
65        String path = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
66        mMediaSet = mDataManager.getMediaSet(path);
67    }
68
69    public MediaSetLoader(Context context, String path) {
70        super(context);
71        mDataManager = DataManager.from(getContext());
72        mMediaSet = mDataManager.getMediaSet(path);
73    }
74
75    @Override
76    protected void onStartLoading() {
77        super.onStartLoading();
78        mMediaSet.addContentListener(mObserver);
79        mSyncTask = mMediaSet.requestSync(sNullListener);
80        forceLoad();
81    }
82
83    @Override
84    protected boolean onCancelLoad() {
85        if (mSyncTask != null) {
86            mSyncTask.cancel();
87            mSyncTask = null;
88        }
89        return super.onCancelLoad();
90    }
91
92    @Override
93    protected void onStopLoading() {
94        super.onStopLoading();
95        cancelLoad();
96        mMediaSet.removeContentListener(mObserver);
97    }
98
99    @Override
100    protected void onReset() {
101        super.onReset();
102        onStopLoading();
103    }
104
105    @Override
106    public Cursor loadInBackground() {
107        // TODO: This probably doesn't work
108        mMediaSet.reload();
109        final MatrixCursor cursor = new MatrixCursor(AlbumSetLoader.PROJECTION);
110        final Object[] row = new Object[AlbumSetLoader.PROJECTION.length];
111        int count = mMediaSet.getSubMediaSetCount();
112        ArrayList<MediaItem> coverItems = new ArrayList<MediaItem>(count);
113        for (int i = 0; i < count; i++) {
114            MediaSet m = mMediaSet.getSubMediaSet(i);
115            m.reload();
116            row[AlbumSetLoader.INDEX_ID] = i;
117            row[AlbumSetLoader.INDEX_TITLE] = m.getName();
118            row[AlbumSetLoader.INDEX_COUNT] = m.getMediaItemCount();
119            row[AlbumSetLoader.INDEX_SUPPORTED_OPERATIONS] = m.getSupportedOperations();
120            MediaItem coverItem = m.getCoverMediaItem();
121            if (coverItem != null) {
122                row[AlbumSetLoader.INDEX_TIMESTAMP] = coverItem.getDateInMs();
123            }
124            coverItems.add(coverItem);
125            cursor.addRow(row);
126        }
127        synchronized (mMediaSet) {
128            mCoverItems = coverItems;
129        }
130        return cursor;
131    }
132
133    @Override
134    public Drawable drawableForItem(Cursor item, Drawable recycle) {
135        BitmapJobDrawable drawable = null;
136        if (recycle == null || !(recycle instanceof BitmapJobDrawable)) {
137            drawable = new BitmapJobDrawable();
138        } else {
139            drawable = (BitmapJobDrawable) recycle;
140        }
141        int index = item.getInt(AlbumSetLoader.INDEX_ID);
142        drawable.setMediaItem(mCoverItems.get(index));
143        return drawable;
144    }
145
146    public static int getThumbnailSize() {
147        return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL);
148    }
149
150    @Override
151    public Uri uriForItem(Cursor item) {
152        int index = item.getInt(AlbumSetLoader.INDEX_ID);
153        MediaSet ms = mMediaSet.getSubMediaSet(index);
154        return ms == null ? null : ms.getContentUri();
155    }
156
157    @Override
158    public ArrayList<Uri> urisForSubItems(Cursor item) {
159        int index = item.getInt(AlbumSetLoader.INDEX_ID);
160        MediaSet ms = mMediaSet.getSubMediaSet(index);
161        if (ms == null) return null;
162        final ArrayList<Uri> result = new ArrayList<Uri>();
163        ms.enumerateMediaItems(new MediaSet.ItemConsumer() {
164            @Override
165            public void consume(int index, MediaItem item) {
166                if (item != null) {
167                    result.add(item.getContentUri());
168                }
169            }
170        });
171        return result;
172    }
173
174    @Override
175    public void deleteItemWithPath(Object path) {
176        MediaObject o = mDataManager.getMediaObject((Path) path);
177        if (o != null) {
178            o.delete();
179        }
180    }
181
182    @Override
183    public Object getPathForItem(Cursor item) {
184        int index = item.getInt(AlbumSetLoader.INDEX_ID);
185        MediaSet ms = mMediaSet.getSubMediaSet(index);
186        if (ms != null) {
187            return ms.getPath();
188        }
189        return null;
190    }
191}
192