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