1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.data;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.net.Uri;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
222b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.app.GalleryApp;
232b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.HashSet;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
27705dc819661cb8c8e839a04577b0641bd6caad53John Reckpublic class ClusterAlbumSet extends MediaSet implements ContentListener {
287817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @SuppressWarnings("unused")
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "ClusterAlbumSet";
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private GalleryApp mApplication;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private MediaSet mBaseSet;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mKind;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ArrayList<ClusterAlbum> mAlbums = new ArrayList<ClusterAlbum>();
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mFirstReloadDone;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ClusterAlbumSet(Path path, GalleryApp application,
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            MediaSet baseSet, int kind) {
38705dc819661cb8c8e839a04577b0641bd6caad53John Reck        super(path, INVALID_DATA_VERSION);
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mApplication = application;
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mBaseSet = baseSet;
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mKind = kind;
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        baseSet.addContentListener(this);
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public MediaSet getSubMediaSet(int index) {
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mAlbums.get(index);
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getSubMediaSetCount() {
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mAlbums.size();
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getName() {
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mBaseSet.getName();
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
61705dc819661cb8c8e839a04577b0641bd6caad53John Reck    public long reload() {
62705dc819661cb8c8e839a04577b0641bd6caad53John Reck        if (mBaseSet.reload() > mDataVersion) {
63705dc819661cb8c8e839a04577b0641bd6caad53John Reck            if (mFirstReloadDone) {
64705dc819661cb8c8e839a04577b0641bd6caad53John Reck                updateClustersContents();
65705dc819661cb8c8e839a04577b0641bd6caad53John Reck            } else {
66705dc819661cb8c8e839a04577b0641bd6caad53John Reck                updateClusters();
67705dc819661cb8c8e839a04577b0641bd6caad53John Reck                mFirstReloadDone = true;
68705dc819661cb8c8e839a04577b0641bd6caad53John Reck            }
69705dc819661cb8c8e839a04577b0641bd6caad53John Reck            mDataVersion = nextVersionNumber();
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
71705dc819661cb8c8e839a04577b0641bd6caad53John Reck        return mDataVersion;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
747817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onContentDirty() {
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        notifyContentChanged();
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateClusters() {
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mAlbums.clear();
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Clustering clustering;
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Context context = mApplication.getAndroidContext();
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        switch (mKind) {
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            case ClusterSource.CLUSTER_ALBUMSET_TIME:
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                clustering = new TimeClustering(context);
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            case ClusterSource.CLUSTER_ALBUMSET_LOCATION:
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                clustering = new LocationClustering(context);
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            case ClusterSource.CLUSTER_ALBUMSET_TAG:
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                clustering = new TagClustering(context);
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            case ClusterSource.CLUSTER_ALBUMSET_FACE:
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                clustering = new FaceClustering(context);
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            default: /* CLUSTER_ALBUMSET_SIZE */
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                clustering = new SizeClustering(context);
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        clustering.run(mBaseSet);
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int n = clustering.getNumberOfClusters();
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        DataManager dataManager = mApplication.getDataManager();
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0; i < n; i++) {
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Path childPath;
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String childName = clustering.getClusterName(i);
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mKind == ClusterSource.CLUSTER_ALBUMSET_TAG) {
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                childPath = mPath.getChild(Uri.encode(childName));
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else if (mKind == ClusterSource.CLUSTER_ALBUMSET_SIZE) {
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                long minSize = ((SizeClustering) clustering).getMinSize(i);
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                childPath = mPath.getChild(minSize);
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                childPath = mPath.getChild(i);
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
115676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin
116676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin            ClusterAlbum album;
117676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin            synchronized (DataManager.LOCK) {
118676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                album = (ClusterAlbum) dataManager.peekMediaObject(childPath);
119676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                if (album == null) {
120676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                    album = new ClusterAlbum(childPath, dataManager, this);
121676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                }
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            album.setMediaItems(clustering.getCluster(i));
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            album.setName(childName);
12504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            album.setCoverMediaItem(clustering.getClusterCover(i));
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mAlbums.add(album);
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateClustersContents() {
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        final HashSet<Path> existing = new HashSet<Path>();
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mBaseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
1337817979db0c52ffeacb951625b1e821eba303285Ahbong Chang            @Override
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void consume(int index, MediaItem item) {
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                existing.add(item.getPath());
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        });
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int n = mAlbums.size();
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The loop goes backwards because we may remove empty albums from
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // mAlbums.
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = n - 1; i >= 0; i--) {
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ArrayList<Path> oldPaths = mAlbums.get(i).getMediaItems();
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ArrayList<Path> newPaths = new ArrayList<Path>();
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int m = oldPaths.size();
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int j = 0; j < m; j++) {
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Path p = oldPaths.get(j);
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (existing.contains(p)) {
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    newPaths.add(p);
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mAlbums.get(i).setMediaItems(newPaths);
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (newPaths.isEmpty()) {
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mAlbums.remove(i);
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
160