ClusterAlbumSet.java revision f4f43e7dbc85ab8b7437e8f1d6ab0317470e70b6
1/*
2 * Copyright (C) 2010 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.gallery3d.data;
18
19import android.content.Context;
20import android.net.Uri;
21
22import com.android.gallery3d.app.GalleryApp;
23
24import java.util.ArrayList;
25import java.util.HashSet;
26
27public class ClusterAlbumSet extends MediaSetWrapper implements ContentListener {
28    @SuppressWarnings("unused")
29    private static final String TAG = "ClusterAlbumSet";
30    private GalleryApp mApplication;
31    private MediaSet mBaseSet;
32    private int mKind;
33    private ArrayList<ClusterAlbum> mAlbums = new ArrayList<ClusterAlbum>();
34    private boolean mFirstReloadDone;
35
36    public ClusterAlbumSet(Path path, GalleryApp application,
37            MediaSet baseSet, int kind) {
38        super(baseSet, path, INVALID_DATA_VERSION);
39        mApplication = application;
40        mBaseSet = baseSet;
41        mKind = kind;
42        baseSet.addContentListener(this);
43    }
44
45    @Override
46    public MediaSet getSubMediaSet(int index) {
47        return mAlbums.get(index);
48    }
49
50    @Override
51    public int getSubMediaSetCount() {
52        return mAlbums.size();
53    }
54
55    @Override
56    public String getName() {
57        return mBaseSet.getName();
58    }
59
60    @Override
61    protected boolean isDirtyLocked() {
62        return super.isDirtyLocked()
63                || !mFirstReloadDone;
64    }
65
66    @Override
67    public void load() throws InterruptedException {
68        super.load();
69        if (mFirstReloadDone) {
70            updateClustersContents();
71        } else {
72            updateClusters();
73            mFirstReloadDone = true;
74        }
75    }
76
77    @Override
78    public void onContentDirty() {
79        notifyContentChanged();
80    }
81
82    private void updateClusters() {
83        mAlbums.clear();
84        Clustering clustering;
85        Context context = mApplication.getAndroidContext();
86        switch (mKind) {
87            case ClusterSource.CLUSTER_ALBUMSET_TIME:
88                clustering = new TimeClustering(context);
89                break;
90            case ClusterSource.CLUSTER_ALBUMSET_LOCATION:
91                clustering = new LocationClustering(context);
92                break;
93            case ClusterSource.CLUSTER_ALBUMSET_TAG:
94                clustering = new TagClustering(context);
95                break;
96            case ClusterSource.CLUSTER_ALBUMSET_FACE:
97                clustering = new FaceClustering(context);
98                break;
99            default: /* CLUSTER_ALBUMSET_SIZE */
100                clustering = new SizeClustering(context);
101                break;
102        }
103
104        clustering.run(mBaseSet);
105        int n = clustering.getNumberOfClusters();
106        DataManager dataManager = mApplication.getDataManager();
107        for (int i = 0; i < n; i++) {
108            Path childPath;
109            String childName = clustering.getClusterName(i);
110            if (mKind == ClusterSource.CLUSTER_ALBUMSET_TAG) {
111                childPath = mPath.getChild(Uri.encode(childName));
112            } else if (mKind == ClusterSource.CLUSTER_ALBUMSET_SIZE) {
113                long minSize = ((SizeClustering) clustering).getMinSize(i);
114                childPath = mPath.getChild(minSize);
115            } else {
116                childPath = mPath.getChild(i);
117            }
118
119            ClusterAlbum album;
120            synchronized (DataManager.LOCK) {
121                album = (ClusterAlbum) dataManager.peekMediaObject(childPath);
122                if (album == null) {
123                    album = new ClusterAlbum(childPath, dataManager, this);
124                }
125            }
126            album.setMediaItems(clustering.getCluster(i));
127            album.setName(childName);
128            album.setCoverMediaItem(clustering.getClusterCover(i));
129            mAlbums.add(album);
130        }
131    }
132
133    private void updateClustersContents() {
134        final HashSet<Path> existing = new HashSet<Path>();
135        mBaseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
136            @Override
137            public void consume(int index, MediaItem item) {
138                existing.add(item.getPath());
139            }
140        });
141
142        int n = mAlbums.size();
143
144        // The loop goes backwards because we may remove empty albums from
145        // mAlbums.
146        for (int i = n - 1; i >= 0; i--) {
147            ArrayList<Path> oldPaths = mAlbums.get(i).getMediaItems();
148            ArrayList<Path> newPaths = new ArrayList<Path>();
149            int m = oldPaths.size();
150            for (int j = 0; j < m; j++) {
151                Path p = oldPaths.get(j);
152                if (existing.contains(p)) {
153                    newPaths.add(p);
154                }
155            }
156            mAlbums.get(i).setMediaItems(newPaths);
157            if (newPaths.isEmpty()) {
158                mAlbums.remove(i);
159            }
160        }
161    }
162}
163