1/*
2 * Copyright (C) 2011 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.graphics.Rect;
21
22import com.android.gallery3d.R;
23import com.android.gallery3d.picasasource.PicasaSource;
24
25import java.util.ArrayList;
26import java.util.TreeMap;
27
28public class FaceClustering extends Clustering {
29    @SuppressWarnings("unused")
30    private static final String TAG = "FaceClustering";
31
32    private FaceCluster[] mClusters;
33    private String mUntaggedString;
34    private Context mContext;
35
36    private class FaceCluster {
37        ArrayList<Path> mPaths = new ArrayList<Path>();
38        String mName;
39        MediaItem mCoverItem;
40        Rect mCoverRegion;
41        int mCoverFaceIndex;
42
43        public FaceCluster(String name) {
44            mName = name;
45        }
46
47        public void add(MediaItem item, int faceIndex) {
48            Path path = item.getPath();
49            mPaths.add(path);
50            Face[] faces = item.getFaces();
51            if (faces != null) {
52                Face face = faces[faceIndex];
53                if (mCoverItem == null) {
54                    mCoverItem = item;
55                    mCoverRegion = face.getPosition();
56                    mCoverFaceIndex = faceIndex;
57                } else {
58                    Rect region = face.getPosition();
59                    if (mCoverRegion.width() < region.width() &&
60                            mCoverRegion.height() < region.height()) {
61                        mCoverItem = item;
62                        mCoverRegion = face.getPosition();
63                        mCoverFaceIndex = faceIndex;
64                    }
65                }
66            }
67        }
68
69        public int size() {
70            return mPaths.size();
71        }
72
73        public MediaItem getCover() {
74            if (mCoverItem != null) {
75                if (PicasaSource.isPicasaImage(mCoverItem)) {
76                    return PicasaSource.getFaceItem(mContext, mCoverItem, mCoverFaceIndex);
77                } else {
78                    return mCoverItem;
79                }
80            }
81            return null;
82        }
83    }
84
85    public FaceClustering(Context context) {
86        mUntaggedString = context.getResources().getString(R.string.untagged);
87        mContext = context;
88    }
89
90    @Override
91    public void run(MediaSet baseSet) {
92        final TreeMap<Face, FaceCluster> map =
93                new TreeMap<Face, FaceCluster>();
94        final FaceCluster untagged = new FaceCluster(mUntaggedString);
95
96        baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
97            @Override
98            public void consume(int index, MediaItem item) {
99                Face[] faces = item.getFaces();
100                if (faces == null || faces.length == 0) {
101                    untagged.add(item, -1);
102                    return;
103                }
104                for (int j = 0; j < faces.length; j++) {
105                    Face face = faces[j];
106                    FaceCluster cluster = map.get(face);
107                    if (cluster == null) {
108                        cluster = new FaceCluster(face.getName());
109                        map.put(face, cluster);
110                    }
111                    cluster.add(item, j);
112                }
113            }
114        });
115
116        int m = map.size();
117        mClusters = map.values().toArray(new FaceCluster[m + ((untagged.size() > 0) ? 1 : 0)]);
118        if (untagged.size() > 0) {
119            mClusters[m] = untagged;
120        }
121    }
122
123    @Override
124    public int getNumberOfClusters() {
125        return mClusters.length;
126    }
127
128    @Override
129    public ArrayList<Path> getCluster(int index) {
130        return mClusters[index].mPaths;
131    }
132
133    @Override
134    public String getClusterName(int index) {
135        return mClusters[index].mName;
136    }
137
138    @Override
139    public MediaItem getClusterCover(int index) {
140        return mClusters[index].getCover();
141    }
142}
143