1a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney/*
2a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Copyright (C) 2010 The Android Open Source Project
3a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney *
4a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Licensed under the Apache License, Version 2.0 (the "License");
5a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * you may not use this file except in compliance with the License.
6a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * You may obtain a copy of the License at
7a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney *
8a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney *      http://www.apache.org/licenses/LICENSE-2.0
9a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney *
10a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Unless required by applicable law or agreed to in writing, software
11a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * distributed under the License is distributed on an "AS IS" BASIS,
12a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * See the License for the specific language governing permissions and
14a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * limitations under the License.
15a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */
16a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
17a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinneypackage com.android.quicksearchbox;
18a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
19b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport com.google.common.annotations.VisibleForTesting;
20b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
2187e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport android.util.Log;
2287e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert
2387e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.Iterator;
2487e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.LinkedList;
25a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
26a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney/**
27a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * A promoter that gives preference to suggestions from higher ranking corpora.
28a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */
29af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwoodpublic class RankAwarePromoter extends AbstractPromoter {
30a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
31b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert    private static final boolean DBG = false;
32bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert    private static final String TAG = "QSB.RankAwarePromoter";
33bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert
3427691bfcdcf3d2918b45bfadd57b08547c317ce5Mathew Inwood    public RankAwarePromoter(Config config, SuggestionFilter filter, Promoter next) {
3527691bfcdcf3d2918b45bfadd57b08547c317ce5Mathew Inwood        super(filter, next, config);
36b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
37b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
38af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood    @Override
3927691bfcdcf3d2918b45bfadd57b08547c317ce5Mathew Inwood    public void doPickPromoted(Suggestions suggestions,
4039bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            int maxPromoted, ListSuggestionCursor promoted) {
41b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        promoteSuggestions(suggestions.getCorpusResults(), maxPromoted, promoted);
42b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
43a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
44b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    @VisibleForTesting
45b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    void promoteSuggestions(Iterable<CorpusResult> suggestions, int maxPromoted,
46b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            ListSuggestionCursor promoted) {
47bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert        if (DBG) Log.d(TAG, "Available results: " + suggestions);
48bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert
499a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // Split non-empty results into important suggestions and not-so-important
509a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // suggestions, each corpus's cursor positioned at the first suggestion.
519a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        LinkedList<CorpusResult> highRankingSuggestions = new LinkedList<CorpusResult>();
529a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        LinkedList<CorpusResult> lowRankingSuggestions = new LinkedList<CorpusResult>();
539a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        partitionSuggestionsByRank(suggestions, highRankingSuggestions, lowRankingSuggestions);
549a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
559a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // Top results, evenly distributed between each high-ranking corpus.
569a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        promoteTopSuggestions(highRankingSuggestions, promoted, maxPromoted);
579a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
589a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // Then try to fill promoted list with the remaining high-ranking suggestions,
599a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // and then use the low-ranking suggestions if the list isn't full yet.
609a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        promoteEquallyFromEachCorpus(highRankingSuggestions, promoted, maxPromoted);
619a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        promoteEquallyFromEachCorpus(lowRankingSuggestions, promoted, maxPromoted);
629a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
639a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        if (DBG) Log.d(TAG, "Returning " + promoted.toString());
649a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    }
65a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
669a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    /**
679a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * Shares the top slots evenly among each of the high-ranking (default) corpora.
689a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *
699a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * The corpora will appear in the promoted list in the order they are listed
709a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * among the incoming suggestions (this method doesn't change their order).
719a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     */
729a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    private void promoteTopSuggestions(LinkedList<CorpusResult> highRankingSuggestions,
739a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            ListSuggestionCursor promoted, int maxPromoted) {
74fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood
759a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        int slotsLeft = getSlotsLeft(promoted, maxPromoted);
769a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        if (slotsLeft > 0 && !highRankingSuggestions.isEmpty()) {
77fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood            int slotsToFill = Math.min(getSlotsAboveKeyboard() - promoted.getCount(), slotsLeft);
789a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
7939bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            if (slotsToFill > 0) {
809a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                int stripeSize = Math.max(1, slotsToFill / highRankingSuggestions.size());
819a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                roundRobin(highRankingSuggestions, slotsToFill, stripeSize, promoted);
8239bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            }
8339bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        }
849a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    }
859a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
869a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    /**
879a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * Tries to promote the same number of elements from each corpus.
889a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *
899a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * The corpora will appear in the promoted list in the order they are listed
909a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * among the incoming suggestions (this method doesn't change their order).
919a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     */
929a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    private void promoteEquallyFromEachCorpus(LinkedList<CorpusResult> suggestions,
939a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            ListSuggestionCursor promoted, int maxPromoted) {
94a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
959a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        int slotsLeft = getSlotsLeft(promoted, maxPromoted);
969a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        if (slotsLeft == 0) {
979a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            // No more items to add.
989a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            return;
99a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        }
100a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
1019a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        if (suggestions.isEmpty()) {
1029a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            return;
103a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        }
104bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert
1059a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        int stripeSize = Math.max(1, slotsLeft / suggestions.size());
1069a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        roundRobin(suggestions, slotsLeft, stripeSize, promoted);
1079a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
1089a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // We may still have a few slots left
1099a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        slotsLeft = getSlotsLeft(promoted, maxPromoted);
1109a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        roundRobin(suggestions, slotsLeft, slotsLeft, promoted);
1119a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    }
1129a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
1139a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    /**
1149a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * Partitions the suggestions into "important" (high-ranking)
1159a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * and "not-so-important" (low-ranking) suggestions, dependent on the
1169a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * rank of the corpus the result is part of.
1179a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *
1189a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * @param suggestions
1199a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * @param highRankingSuggestions These should be displayed first to the
1209a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *     user.
1219a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     * @param lowRankingSuggestions These should be displayed if the
1229a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *     high-ranking suggestions don't fill all the available space in the
1239a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     *     result view.
1249a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay     */
1259a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    private void partitionSuggestionsByRank(Iterable<CorpusResult> suggestions,
1269a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            LinkedList<CorpusResult> highRankingSuggestions,
1279a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            LinkedList<CorpusResult> lowRankingSuggestions) {
1289a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
1299a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        for (CorpusResult result : suggestions) {
1309a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            if (result.getCount() > 0) {
1319a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                result.moveTo(0);
1329a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                Corpus corpus = result.getCorpus();
1339a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                if (isCorpusHighlyRanked(corpus)) {
1349a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                    highRankingSuggestions.add(result);
1359a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                } else {
1369a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                    lowRankingSuggestions.add(result);
1379a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                }
1389a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay            }
1399a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        }
1409a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    }
1419a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
1429a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    private boolean isCorpusHighlyRanked(Corpus corpus) {
1439a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // The default corpora shipped with QSB (apps, etc.) are
1449a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // more important than ones that were registered later.
1459a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        return corpus == null || corpus.isCorpusDefaultEnabled();
1469a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    }
1479a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay
1489a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay    private int getSlotsLeft(ListSuggestionCursor promoted, int maxPromoted) {
1499a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // It's best to calculate this after each addition because duplicates
1509a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        // may get filtered out automatically in the list of promoted items.
1519a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay        return Math.max(0, maxPromoted - promoted.getCount());
152a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    }
153a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
15439bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney    private int getSlotsAboveKeyboard() {
155af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood        return getConfig().getNumSuggestionsAboveKeyboard();
15639bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney    }
15739bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
158a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    /**
159a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * Promotes "stripes" of suggestions from each corpus.
160a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     *
161a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param results     the list of CorpusResults from which to promote.
162a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     *                    Exhausted CorpusResults are removed from the list.
163a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param maxPromoted maximum number of suggestions to promote.
164a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param stripeSize  number of suggestions to take from each corpus.
165a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param promoted    the list to which promoted suggestions are added.
166a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @return the number of suggestions actually promoted.
167a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     */
168a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    private int roundRobin(LinkedList<CorpusResult> results, int maxPromoted, int stripeSize,
169a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney            ListSuggestionCursor promoted) {
170a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        int count = 0;
171a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        if (maxPromoted > 0 && !results.isEmpty()) {
172a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney            for (Iterator<CorpusResult> iter = results.iterator();
173a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                 count < maxPromoted && iter.hasNext();) {
174a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                CorpusResult result = iter.next();
175a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                count += promote(result, stripeSize, promoted);
176a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                if (result.getPosition() == result.getCount()) {
177a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                    iter.remove();
178a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney                }
179a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney            }
180a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        }
181a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney        return count;
182a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    }
183a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney
184a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    /**
185a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * Copies suggestions from a SuggestionCursor to the list of promoted suggestions.
186a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     *
187a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param cursor from which to copy the suggestions
188a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param count maximum number of suggestions to copy
189a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @param promoted the list to which to add the suggestions
190a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     * @return the number of suggestions actually copied.
191a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney     */
192a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    private int promote(SuggestionCursor cursor, int count, ListSuggestionCursor promoted) {
19387e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert        if (count < 1 || cursor.getPosition() >= cursor.getCount()) {
19487e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert            return 0;
19587e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert        }
196b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        int addedCount = 0;
19787e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert        do {
198b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            if (accept(cursor)) {
1999a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                if (promoted.add(new SuggestionPosition(cursor))) {
2009a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                    // Added successfully (wasn't already promoted).
2019a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                    addedCount++;
2029a8c6b416ac7ab00998d3496226712f1d442838fPeter Visontay                }
203b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            }
204b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        } while (cursor.moveToNext() && addedCount < count);
205b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return addedCount;
206a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney    }
207b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
208a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney}
209