1 /* 2 * Copyright (C) 2010 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.quicksearchbox; 18 19 import com.android.quicksearchbox.util.CachedLater; 20 import com.android.quicksearchbox.util.Consumer; 21 22 import android.database.DataSetObserver; 23 import android.util.Log; 24 25 import java.util.ArrayList; 26 import java.util.Collection; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * A corpus ranker that uses corpus scores from the shortcut repository to rank 34 * corpora. 35 */ 36 public class DefaultCorpusRanker implements CorpusRanker { 37 38 private static final boolean DBG = false; 39 private static final String TAG = "QSB.DefaultCorpusRanker"; 40 41 private final ShortcutRepository mShortcuts; 42 43 private final Corpora mCorpora; 44 45 // Cached list of ranked corpora. 46 private final RankedCorporaCache mRankedCorpora; 47 48 /** 49 * Creates a new default corpus ranker. 50 * 51 * @param corpora Corpora to rank. 52 * @param shortcuts Shortcut repository for getting corpus scores. 53 */ 54 public DefaultCorpusRanker(Corpora corpora, ShortcutRepository shortcuts) { 55 mCorpora = corpora; 56 mCorpora.registerDataSetObserver(new CorporaObserver()); 57 mShortcuts = shortcuts; 58 mRankedCorpora = new RankedCorporaCache(); 59 } 60 61 public void getCorporaInAll(Consumer<List<Corpus>> consumer) { 62 mRankedCorpora.getLater(consumer); 63 } 64 65 public void clear() { 66 mRankedCorpora.clear(); 67 } 68 69 private class CorporaObserver extends DataSetObserver { 70 @Override 71 public void onChanged() { 72 clear(); 73 } 74 } 75 76 private class RankedCorporaCache extends CachedLater<List<Corpus>> { 77 78 @Override 79 protected void create() { 80 mShortcuts.getCorpusScores(new Consumer<Map<String,Integer>>(){ 81 public boolean consume(Map<String, Integer> clickScores) { 82 Collection<Corpus> enabledCorpora = mCorpora.getCorporaInAll(); 83 if (DBG) Log.d(TAG, "Ranking: " + enabledCorpora); 84 ArrayList<Corpus> ordered = new ArrayList<Corpus>(enabledCorpora); 85 Collections.sort(ordered, new CorpusComparator(clickScores)); 86 87 if (DBG) Log.d(TAG, "Click scores: " + clickScores); 88 if (DBG) Log.d(TAG, "Ordered: " + ordered); 89 90 store(ordered); 91 return true; 92 } 93 }); 94 } 95 96 } 97 98 private static class CorpusComparator implements Comparator<Corpus> { 99 private final Map<String,Integer> mClickScores; 100 101 public CorpusComparator(Map<String,Integer> clickScores) { 102 mClickScores = clickScores; 103 } 104 105 public int compare(Corpus corpus1, Corpus corpus2) { 106 boolean corpus1IsDefault = corpus1.isCorpusDefaultEnabled(); 107 boolean corpus2IsDefault = corpus2.isCorpusDefaultEnabled(); 108 109 if (corpus1IsDefault != corpus2IsDefault) { 110 // Default corpora always come before non-default 111 return corpus1IsDefault ? -1 : 1; 112 } 113 114 // Then by descending score 115 int scoreDiff = getCorpusScore(corpus2) - getCorpusScore(corpus1); 116 if (scoreDiff != 0) { 117 return scoreDiff; 118 } 119 120 // Finally by name 121 return corpus1.getLabel().toString().compareTo(corpus2.getLabel().toString()); 122 } 123 124 /** 125 * Scores a corpus. Higher score is better. 126 */ 127 private int getCorpusScore(Corpus corpus) { 128 // Web corpus always comes first 129 if (corpus.isWebCorpus()) { 130 return Integer.MAX_VALUE; 131 } 132 // Then use click score 133 return getClickScore(corpus); 134 } 135 136 private int getClickScore(Corpus corpus) { 137 if (mClickScores == null) return 0; 138 Integer clickScore = mClickScores.get(corpus.getName()); 139 return clickScore == null ? 0 : clickScore; 140 } 141 } 142 143 } 144