1fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood/*
2fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * Copyright (C) 2010 The Android Open Source Project
3fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood *
4fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * Licensed under the Apache License, Version 2.0 (the "License");
5fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * you may not use this file except in compliance with the License.
6fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * You may obtain a copy of the License at
7fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood *
8fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood *      http://www.apache.org/licenses/LICENSE-2.0
9fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood *
10fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * Unless required by applicable law or agreed to in writing, software
11fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * distributed under the License is distributed on an "AS IS" BASIS,
12fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * See the License for the specific language governing permissions and
14fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * limitations under the License.
15fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood */
16fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodpackage com.android.quicksearchbox.ui;
17fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
187a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.CorpusResult;
19f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwoodimport com.android.quicksearchbox.ListSuggestionCursor;
207a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.R;
217a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.Suggestion;
227a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.SuggestionCursor;
237a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.SuggestionPosition;
24f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwoodimport com.android.quicksearchbox.SuggestionUtils;
257a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport com.android.quicksearchbox.Suggestions;
267a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
277a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport android.content.Context;
28f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwoodimport android.util.Log;
297a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport android.view.LayoutInflater;
30fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.view.View;
31fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.view.ViewGroup;
32fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.widget.BaseExpandableListAdapter;
33fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.widget.ExpandableListAdapter;
34fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
357a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwoodimport java.util.ArrayList;
36f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwoodimport java.util.HashSet;
377a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
38fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood/**
39fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * Adapter for suggestions list where suggestions are clustered by corpus.
40fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood */
41fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodpublic class ClusteredSuggestionsAdapter extends SuggestionsAdapterBase<ExpandableListAdapter> {
42fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
43f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood    private static final String TAG = "QSB.ClusteredSuggestionsAdapter";
44f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood
457a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    private final static int GROUP_SHIFT = 32;
467a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    private final static long CHILD_MASK = 0xffffffff;
477a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
48fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private final Adapter mAdapter;
497a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    private final Context mContext;
507a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    private final LayoutInflater mInflater;
51fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
5277909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    public ClusteredSuggestionsAdapter(SuggestionViewFactory viewFactory, Context context) {
5377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        super(viewFactory);
54fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mAdapter = new Adapter();
557a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        mContext = context;
567a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
577a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    }
587a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
597a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    @Override
607a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public boolean isEmpty() {
617a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        return mAdapter.getGroupCount() == 0;
627a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    }
637a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
647a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    @Override
65116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood    public boolean willPublishNonPromotedSuggestions() {
66116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood        return true;
67116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood    }
68116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood
69116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood    @Override
707a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public SuggestionPosition getSuggestion(long suggestionId) {
717a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        return mAdapter.getChildById(suggestionId);
72fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
73fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
74fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    @Override
75fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public ExpandableListAdapter getListAdapter() {
76fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mAdapter;
77fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
78fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
79fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    @Override
80fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected void notifyDataSetChanged() {
817a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        mAdapter.buildCorpusGroups();
82fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mAdapter.notifyDataSetChanged();
83fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
84fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
85fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    @Override
86fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected void notifyDataSetInvalidated() {
877a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        mAdapter.buildCorpusGroups();
88fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mAdapter.notifyDataSetInvalidated();
89fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
90fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
91fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private class Adapter extends BaseExpandableListAdapter {
92fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
93f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood        private ArrayList<SuggestionCursor> mCorpusGroups;
947a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
957a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public void buildCorpusGroups() {
967a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            Suggestions suggestions = getSuggestions();
97f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood            SuggestionCursor promoted = getCurrentPromotedSuggestions();
98f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood            HashSet<String> promotedSuggestions = new HashSet<String>();
99f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood            if (promoted != null && promoted.getCount() > 0) {
100f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                promoted.moveTo(0);
101f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                do {
102f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    promotedSuggestions.add(SuggestionUtils.getSuggestionKey(promoted));
103f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                } while (promoted.moveToNext());
104f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood            }
1057a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            if (suggestions == null) {
1067a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                mCorpusGroups = null;
1077a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            } else {
1087a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                if (mCorpusGroups == null) {
109f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    mCorpusGroups = new ArrayList<SuggestionCursor>();
1107a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                } else {
1117a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                    mCorpusGroups.clear();
1127a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                }
1137a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                for (CorpusResult result : suggestions.getCorpusResults()) {
114f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    ListSuggestionCursor corpusSuggestions = new ListSuggestionCursor(
115f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                            result.getUserQuery());
116f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    for (int i = 0; i < result.getCount(); ++i) {
117f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                        result.moveTo(i);
118f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                        if (!result.isWebSearchSuggestion()) {
119af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood                            if (!promotedSuggestions.contains(
120f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                                    SuggestionUtils.getSuggestionKey(result))) {
121f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                                corpusSuggestions.add(new SuggestionPosition(result, i));
122f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                            }
123f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                        }
124f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    }
125f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                    if (corpusSuggestions.getCount() > 0) {
126f32ccb142919068f22ac0a0c19459c9153f70ecaMathew Inwood                        mCorpusGroups.add(corpusSuggestions);
1277a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                    }
1287a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                }
1297a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            }
1307a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1317a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
1327a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        @Override
1337a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public long getCombinedChildId(long groupId, long childId) {
13445f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            // add one to the child ID to ensure that the group elements do not have the same ID
13545f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            // as the first child within the group.
13645f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            return (groupId << GROUP_SHIFT) | ((childId + 1) & CHILD_MASK);
1377a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1387a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
139fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
1407a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public long getCombinedGroupId(long groupId) {
1417a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return groupId << GROUP_SHIFT;
1427a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1437a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
1447a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public int getChildPosition(long childId) {
14545f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            return (int) (childId & CHILD_MASK) - 1;
1467a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1477a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
1487a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public int getGroupPosition(long childId) {
1497a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return (int) ((childId >> GROUP_SHIFT) & CHILD_MASK);
1507a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1517a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
1527a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        @Override
1537a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public Suggestion getChild(int groupPosition, int childPosition) {
1547a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            SuggestionCursor c = getGroup(groupPosition);
155f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            if (c != null) {
156f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                c.moveTo(childPosition);
1577a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                return new SuggestionPosition(c, childPosition);
158f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            }
159f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            return null;
1607a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
1617a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
1627a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public SuggestionPosition getChildById(long childId) {
163f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            SuggestionCursor groupCursor = getGroup(getGroupPosition(childId));
164f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            if (groupCursor != null) {
165f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                return new SuggestionPosition(groupCursor, getChildPosition(childId));
166f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            } else {
167f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                Log.w(TAG, "Invalid childId " + Long.toHexString(childId) + " (invalid group)");
168f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                return null;
169f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            }
170fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
171fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
172fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
173fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public long getChildId(int groupPosition, int childPosition) {
1747a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return childPosition;
175fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
176fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
177fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
178fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
179fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                View convertView, ViewGroup parent) {
1807a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            SuggestionCursor cursor = getGroup(groupPosition);
181f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            if (cursor == null) return null;
1827a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return getView(cursor, childPosition, getCombinedChildId(groupPosition, childPosition),
1837a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                    convertView, parent);
184fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
185fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
186fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
187fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public int getChildrenCount(int groupPosition) {
188f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            SuggestionCursor group = getGroup(groupPosition);
189f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood            return group == null ? 0 : group.getCount();
190fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
191fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
192fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
1937a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public SuggestionCursor getGroup(int groupPosition) {
1947a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            if (groupPosition < promotedGroupCount()) {
1957a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                return getCurrentPromotedSuggestions();
1967a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            } else {
197f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                int pos = groupPosition - promotedGroupCount();
198f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                if ((pos < 0 ) || (pos >= mCorpusGroups.size())) return null;
199f919c948d7dc585d1ca5fe5f357ec327ea2323c4Mathew Inwood                return mCorpusGroups.get(pos);
2007a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            }
2017a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
2027a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
2037a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        private int promotedCount() {
2047a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            SuggestionCursor promoted = getCurrentPromotedSuggestions();
2057a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return (promoted == null ? 0 : promoted.getCount());
2067a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
2077a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
2087a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        private int promotedGroupCount() {
209af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood            return (promotedCount() == 0) ? 0 : 1;
2107a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
2117a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
2127a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        private int corpusGroupCount() {
2137a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return mCorpusGroups == null ? 0 : mCorpusGroups.size();
214fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
215fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
216fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
217fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public int getGroupCount() {
2187a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return promotedGroupCount() + corpusGroupCount();
219fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
220fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
221fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
222fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public long getGroupId(int groupPosition) {
2237a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return groupPosition;
224fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
225fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
226fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
227fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public View getGroupView(
228fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
2297a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            if (convertView == null) {
2307a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                convertView = mInflater.inflate(R.layout.suggestion_group, parent, false);
2317a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            }
2327a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            if (groupPosition == 0) {
2337a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                // don't show the group separator for the first group, to avoid seeing an empty
2347a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                // gap at the top of the list.
2357a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                convertView.getLayoutParams().height = 0;
2367a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            } else {
2377a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                convertView.getLayoutParams().height = mContext.getResources().
2387a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood                        getDimensionPixelSize(R.dimen.suggestion_group_spacing);
2397a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            }
2407a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            // since we've fiddled with the layout params:
2417a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            convertView.requestLayout();
2427a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return convertView;
243fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
244fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
245fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
246fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public boolean hasStableIds() {
247fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            return false;
248fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
249fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
250fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
251fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public boolean isChildSelectable(int groupPosition, int childPosition) {
2527a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return true;
2537a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
2547a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
2557a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        @Override
2567a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public int getChildType(int groupPosition, int childPosition) {
2577a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return getSuggestionViewType(getGroup(groupPosition), childPosition);
258fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
259fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
2607a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        @Override
2617a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public int getChildTypeCount() {
2627a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            return getSuggestionViewTypeCount();
2637a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        }
264fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
265fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
266fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood}
267