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() {
977817979db0c52ffeacb951625b1e821eba303285Ahbong Chang            @Override
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void consume(int index, MediaItem item) {
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Face[] faces = item.getFaces();
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (faces == null || faces.length == 0) {
10104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    untagged.add(item, -1);
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    return;
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                for (int j = 0; j < faces.length; j++) {
10504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    Face face = faces[j];
10604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    FaceCluster cluster = map.get(face);
10704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    if (cluster == null) {
10804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        cluster = new FaceCluster(face.getName());
10904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                        map.put(face, cluster);
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
11104a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen                    cluster.add(item, j);
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        });
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int m = map.size();
11704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        mClusters = map.values().toArray(new FaceCluster[m + ((untagged.size() > 0) ? 1 : 0)]);
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (untagged.size() > 0) {
11904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen            mClusters[m] = untagged;
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getNumberOfClusters() {
12504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters.length;
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ArrayList<Path> getCluster(int index) {
13004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].mPaths;
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getClusterName(int index) {
13504a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].mName;
13604a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    }
13704a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen
13804a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    @Override
13904a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen    public MediaItem getClusterCover(int index) {
14004a9a44fb85263c4590ca68f92adff6f9da360e9Ray Chen        return mClusters[index].getCover();
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
143