ClusteredSuggestionsAdapter.java revision 7a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24
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 */ 16package com.android.quicksearchbox.ui; 17 18import com.android.quicksearchbox.Corpora; 19import com.android.quicksearchbox.CorpusResult; 20import com.android.quicksearchbox.R; 21import com.android.quicksearchbox.Suggestion; 22import com.android.quicksearchbox.SuggestionCursor; 23import com.android.quicksearchbox.SuggestionPosition; 24import com.android.quicksearchbox.Suggestions; 25 26import android.content.Context; 27import android.view.LayoutInflater; 28import android.view.View; 29import android.view.ViewGroup; 30import android.widget.BaseExpandableListAdapter; 31import android.widget.ExpandableListAdapter; 32 33import java.util.ArrayList; 34 35/** 36 * Adapter for suggestions list where suggestions are clustered by corpus. 37 */ 38public class ClusteredSuggestionsAdapter extends SuggestionsAdapterBase<ExpandableListAdapter> { 39 40 private final static int GROUP_SHIFT = 32; 41 private final static long CHILD_MASK = 0xffffffff; 42 43 private final Adapter mAdapter; 44 private final Context mContext; 45 private final LayoutInflater mInflater; 46 47 public ClusteredSuggestionsAdapter(SuggestionViewFactory fallbackFactory, 48 Corpora corpora, Context context) { 49 super(fallbackFactory, corpora); 50 mAdapter = new Adapter(); 51 mContext = context; 52 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 53 } 54 55 @Override 56 public boolean isEmpty() { 57 return mAdapter.getGroupCount() == 0; 58 } 59 60 @Override 61 public SuggestionPosition getSuggestion(long suggestionId) { 62 return mAdapter.getChildById(suggestionId); 63 } 64 65 @Override 66 public ExpandableListAdapter getListAdapter() { 67 return mAdapter; 68 } 69 70 @Override 71 protected void notifyDataSetChanged() { 72 mAdapter.buildCorpusGroups(); 73 mAdapter.notifyDataSetChanged(); 74 } 75 76 @Override 77 protected void notifyDataSetInvalidated() { 78 mAdapter.buildCorpusGroups(); 79 mAdapter.notifyDataSetInvalidated(); 80 } 81 82 private class Adapter extends BaseExpandableListAdapter { 83 84 private ArrayList<CorpusResult> mCorpusGroups; 85 86 public void buildCorpusGroups() { 87 Suggestions suggestions = getSuggestions(); 88 if (suggestions == null) { 89 mCorpusGroups = null; 90 } else { 91 if (mCorpusGroups == null) { 92 mCorpusGroups = new ArrayList<CorpusResult>(); 93 } else { 94 mCorpusGroups.clear(); 95 } 96 // TODO order corpora by usage 97 for (CorpusResult result : suggestions.getCorpusResults()) { 98 if (!result.getCorpus().isWebCorpus() && result.getCount() > 0) { 99 mCorpusGroups.add(result); 100 } 101 } 102 } 103 } 104 105 @Override 106 public long getCombinedChildId(long groupId, long childId) { 107 return (groupId << GROUP_SHIFT) | (childId & CHILD_MASK); 108 } 109 110 @Override 111 public long getCombinedGroupId(long groupId) { 112 return groupId << GROUP_SHIFT; 113 } 114 115 public int getChildPosition(long childId) { 116 return (int) (childId & CHILD_MASK); 117 } 118 119 public int getGroupPosition(long childId) { 120 return (int) ((childId >> GROUP_SHIFT) & CHILD_MASK); 121 } 122 123 @Override 124 public Suggestion getChild(int groupPosition, int childPosition) { 125 SuggestionCursor c = getGroup(groupPosition); 126 c.moveTo(childPosition); 127 return new SuggestionPosition(c, childPosition); 128 } 129 130 public SuggestionPosition getChildById(long childId) { 131 return new SuggestionPosition(getGroup(getGroupPosition(childId)), 132 getChildPosition(getChildPosition(childId))); 133 } 134 135 @Override 136 public long getChildId(int groupPosition, int childPosition) { 137 return childPosition; 138 } 139 140 @Override 141 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, 142 View convertView, ViewGroup parent) { 143 SuggestionCursor cursor = getGroup(groupPosition); 144 return getView(cursor, childPosition, getCombinedChildId(groupPosition, childPosition), 145 convertView, parent); 146 } 147 148 @Override 149 public int getChildrenCount(int groupPosition) { 150 return getGroup(groupPosition).getCount(); 151 } 152 153 @Override 154 public SuggestionCursor getGroup(int groupPosition) { 155 if (groupPosition < promotedGroupCount()) { 156 return getCurrentPromotedSuggestions(); 157 } else { 158 return mCorpusGroups.get(groupPosition - promotedGroupCount()); 159 } 160 } 161 162 private int promotedCount() { 163 SuggestionCursor promoted = getCurrentPromotedSuggestions(); 164 return (promoted == null ? 0 : promoted.getCount()); 165 } 166 167 private int promotedGroupCount() { 168 return promotedCount() == 0 ? 0 : 1; 169 } 170 171 private int corpusGroupCount() { 172 return mCorpusGroups == null ? 0 : mCorpusGroups.size(); 173 } 174 175 @Override 176 public int getGroupCount() { 177 return promotedGroupCount() + corpusGroupCount(); 178 } 179 180 @Override 181 public long getGroupId(int groupPosition) { 182 return groupPosition; 183 } 184 185 @Override 186 public View getGroupView( 187 int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 188 if (convertView == null) { 189 convertView = mInflater.inflate(R.layout.suggestion_group, parent, false); 190 } 191 if (groupPosition == 0) { 192 // don't show the group separator for the first group, to avoid seeing an empty 193 // gap at the top of the list. 194 convertView.getLayoutParams().height = 0; 195 } else { 196 convertView.getLayoutParams().height = mContext.getResources(). 197 getDimensionPixelSize(R.dimen.suggestion_group_spacing); 198 } 199 // since we've fiddled with the layout params: 200 convertView.requestLayout(); 201 return convertView; 202 } 203 204 @Override 205 public boolean hasStableIds() { 206 return false; 207 } 208 209 @Override 210 public boolean isChildSelectable(int groupPosition, int childPosition) { 211 return true; 212 } 213 214 @Override 215 public int getChildType(int groupPosition, int childPosition) { 216 return getSuggestionViewType(getGroup(groupPosition), childPosition); 217 } 218 219 @Override 220 public int getChildTypeCount() { 221 return getSuggestionViewTypeCount(); 222 } 223 } 224 225} 226