1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2011 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;
2004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chenimport android.graphics.Rect;
2104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
2204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chenimport com.android.gallery3d.R;
2304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chenimport com.android.gallery3d.picasasource.PicasaSource;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.TreeMap;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class FaceClustering extends Clustering {
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unused")
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "FaceClustering";
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    private FaceCluster[] mClusters;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private String mUntaggedString;
3404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    private Context mContext;
3504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
3604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    private class FaceCluster {
3704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        ArrayList<Path> mPaths = new ArrayList<Path>();
3804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        String mName;
3904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        MediaItem mCoverItem;
4004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        Rect mCoverRegion;
4104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        int mCoverFaceIndex;
4204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
4304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        public FaceCluster(String name) {
4404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            mName = name;
4504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        }
4604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
4704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        public void add(MediaItem item, int faceIndex) {
4804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            Path path = item.getPath();
4904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            mPaths.add(path);
5004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            Face[] faces = item.getFaces();
5104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            if (faces != null) {
5204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                Face face = faces[faceIndex];
5304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                if (mCoverItem == null) {
5404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    mCoverItem = item;
5504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    mCoverRegion = face.getPosition();
5604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    mCoverFaceIndex = faceIndex;
5704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                } else {
5804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    Rect region = face.getPosition();
5904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    if (mCoverRegion.width() < region.width() &&
6004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                            mCoverRegion.height() < region.height()) {
6104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        mCoverItem = item;
6204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        mCoverRegion = face.getPosition();
6304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        mCoverFaceIndex = faceIndex;
6404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    }
6504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                }
6604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            }
6704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        }
6804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
6904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        public int size() {
7004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            return mPaths.size();
7104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        }
7204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
7304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        public MediaItem getCover() {
7404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            if (mCoverItem != null) {
7504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                if (PicasaSource.isPicasaImage(mCoverItem)) {
7604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    return PicasaSource.getFaceItem(mContext, mCoverItem, mCoverFaceIndex);
7704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                } else {
7804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    return mCoverItem;
7904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                }
8004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            }
8104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            return null;
8204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        }
8304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    }
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public FaceClustering(Context context) {
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mUntaggedString = context.getResources().getString(R.string.untagged);
8704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        mContext = context;
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void run(MediaSet baseSet) {
9204a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        final TreeMap<Face, FaceCluster> map =
9304a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                new TreeMap<Face, FaceCluster>();
9404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        final FaceCluster untagged = new FaceCluster(mUntaggedString);
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        baseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void consume(int index, MediaItem item) {
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Face[] faces = item.getFaces();
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (faces == null || faces.length == 0) {
10004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    untagged.add(item, -1);
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    return;
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                for (int j = 0; j < faces.length; j++) {
10404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    Face face = faces[j];
10504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    FaceCluster cluster = map.get(face);
10604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    if (cluster == null) {
10704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        cluster = new FaceCluster(face.getName());
10804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        map.put(face, cluster);
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
11004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    cluster.add(item, j);
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        });
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int m = map.size();
11604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        mClusters = map.values().toArray(new FaceCluster[m + ((untagged.size() > 0) ? 1 : 0)]);
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (untagged.size() > 0) {
11804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            mClusters[m] = untagged;
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getNumberOfClusters() {
12404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters.length;
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ArrayList<Path> getCluster(int index) {
12904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].mPaths;
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getClusterName(int index) {
13404a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].mName;
13504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    }
13604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
13704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    @Override
13804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    public MediaItem getClusterCover(int index) {
13904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].getCover();
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
142