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 17 package com.android.gallery3d.data; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 22 import com.android.gallery3d.R; 23 import com.android.gallery3d.picasasource.PicasaSource; 24 25 import java.util.ArrayList; 26 import java.util.TreeMap; 27 28 public 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 public void consume(int index, MediaItem item) { 98 Face[] faces = item.getFaces(); 99 if (faces == null || faces.length == 0) { 100 untagged.add(item, -1); 101 return; 102 } 103 for (int j = 0; j < faces.length; j++) { 104 Face face = faces[j]; 105 FaceCluster cluster = map.get(face); 106 if (cluster == null) { 107 cluster = new FaceCluster(face.getName()); 108 map.put(face, cluster); 109 } 110 cluster.add(item, j); 111 } 112 } 113 }); 114 115 int m = map.size(); 116 mClusters = map.values().toArray(new FaceCluster[m + ((untagged.size() > 0) ? 1 : 0)]); 117 if (untagged.size() > 0) { 118 mClusters[m] = untagged; 119 } 120 } 121 122 @Override 123 public int getNumberOfClusters() { 124 return mClusters.length; 125 } 126 127 @Override 128 public ArrayList<Path> getCluster(int index) { 129 return mClusters[index].mPaths; 130 } 131 132 @Override 133 public String getClusterName(int index) { 134 return mClusters[index].mName; 135 } 136 137 @Override 138 public MediaItem getClusterCover(int index) { 139 return mClusters[index].getCover(); 140 } 141 } 142