SearchActivityViewTwoPane.java revision 04780ccd1ef55fca5234cdad4386d7248bb9b3dd
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 17package com.android.quicksearchbox.ui; 18 19import com.android.quicksearchbox.Corpus; 20import com.android.quicksearchbox.Promoter; 21import com.android.quicksearchbox.R; 22import com.android.quicksearchbox.Suggestions; 23 24import android.animation.Animator; 25import android.animation.ObjectAnimator; 26import android.animation.ValueAnimator; 27import android.animation.ValueAnimator.AnimatorUpdateListener; 28import android.content.Context; 29import android.database.DataSetObserver; 30import android.util.AttributeSet; 31import android.util.Log; 32import android.view.Menu; 33import android.view.View; 34import android.view.ViewGroup; 35import android.widget.ExpandableListAdapter; 36import android.widget.ImageView; 37import android.widget.PopupMenu; 38 39/** 40 * Two-pane variant for the search activity view. 41 */ 42public class SearchActivityViewTwoPane extends SearchActivityView { 43 44 private static final int ENTRY_ANIMATION_START_DELAY = 150; // in millis 45 private static final int ENTRY_ANIMATION_DURATION = 150; // in millis 46 private static final float ANIMATION_STARTING_WIDTH_FACTOR = 0.6f; 47 48 private ImageView mMenuButton; 49 50 // View that shows the results other than the query completions 51 private ClusteredSuggestionsView mResultsView; 52 private SuggestionsAdapter<ExpandableListAdapter> mResultsAdapter; 53 private View mResultsHeader; 54 private View mSearchPlate; 55 private boolean mJustCreated; 56 57 public SearchActivityViewTwoPane(Context context) { 58 super(context); 59 } 60 61 public SearchActivityViewTwoPane(Context context, AttributeSet attrs) { 62 super(context, attrs); 63 } 64 65 public SearchActivityViewTwoPane(Context context, AttributeSet attrs, int defStyle) { 66 super(context, attrs, defStyle); 67 } 68 69 @Override 70 protected void onFinishInflate() { 71 super.onFinishInflate(); 72 73 mMenuButton = (ImageView) findViewById(R.id.menu_button); 74 mMenuButton.setOnClickListener(new View.OnClickListener() { 75 public void onClick(View v) { 76 showPopupMenu(); 77 } 78 }); 79 80 mResultsView = (ClusteredSuggestionsView) findViewById(R.id.shortcuts); 81 mResultsAdapter = createClusteredSuggestionsAdapter(); 82 mResultsAdapter.getListAdapter().registerDataSetObserver(new DataSetObserver(){ 83 @Override 84 public void onChanged() { 85 mResultsView.expandAll(); 86 } 87 }); 88 mResultsView.setOnKeyListener(new SuggestionsViewKeyListener()); 89 mResultsView.setFocusable(true); 90 mResultsHeader = findViewById(R.id.shortcut_title); 91 mSearchPlate = findViewById(R.id.left_pane); 92 mJustCreated = true; 93 } 94 95 private void showPopupMenu() { 96 PopupMenu popup = new PopupMenu(getContext(), mMenuButton); 97 Menu menu = popup.getMenu(); 98 getActivity().createMenuItems(menu, false); 99 popup.show(); 100 } 101 102 protected SuggestionsAdapter<ExpandableListAdapter> createClusteredSuggestionsAdapter() { 103 return new DelayingSuggestionsAdapter<ExpandableListAdapter>( 104 new ClusteredSuggestionsAdapter( 105 getQsbApplication().getSuggestionViewFactory(), 106 getContext())); 107 } 108 109 @Override 110 public void onResume() { 111 if (mJustCreated) { 112 setupEntryAnimations(); 113 mJustCreated = false; 114 } 115 } 116 117 @Override 118 public void onPause() { 119 super.onPause(); 120 getActivity().overridePendingTransition(R.anim.fade_in_fast, R.anim.fade_out_fast); 121 } 122 123 private void setupEntryAnimations() { 124 // TODO: Use the left/top of the source bounds to start the animation from 125 final int endingWidth = getResources().getDimensionPixelSize(R.dimen.suggestions_width); 126 final int startingWidth = (int) (endingWidth * ANIMATION_STARTING_WIDTH_FACTOR); 127 128 ViewGroup.LayoutParams params = mSearchPlate.getLayoutParams(); 129 params.width = startingWidth; 130 mSearchPlate.setLayoutParams(params); 131 132 Animator animator = ObjectAnimator.ofInt(mSearchPlate, "alpha", 0, 255); 133 animator.setDuration(ENTRY_ANIMATION_DURATION); 134 ((ValueAnimator)animator).addUpdateListener(new AnimatorUpdateListener() { 135 136 public void onAnimationUpdate(ValueAnimator animator) { 137 ViewGroup.LayoutParams params = mSearchPlate.getLayoutParams(); 138 params.width = startingWidth 139 + (int) ((Integer) animator.getAnimatedValue() / 255f 140 * (endingWidth - startingWidth)); 141 mSearchPlate.setLayoutParams(params); 142 } 143 }); 144 animator.setStartDelay(ENTRY_ANIMATION_START_DELAY); 145 animator.start(); 146 147 } 148 149 @Override 150 public void onStop() { 151 } 152 153 @Override 154 public void start() { 155 super.start(); 156 mResultsAdapter.getListAdapter().registerDataSetObserver(new ResultsObserver()); 157 mResultsView.setSuggestionsAdapter(mResultsAdapter); 158 } 159 160 @Override 161 public void destroy() { 162 mResultsView.setSuggestionsAdapter(null); 163 164 super.destroy(); 165 } 166 167 @Override 168 public void considerHidingInputMethod() { 169 // Don't hide keyboard when interacting with suggestions list 170 } 171 172 @Override 173 public void hideSuggestions() { 174 // Never hiding suggestions view in two-pane UI 175 } 176 177 @Override 178 public void showSuggestions() { 179 // Never hiding suggestions view in two-pane UI 180 } 181 182 @Override 183 public void showCorpusSelectionDialog() { 184 // not used 185 } 186 187 @Override 188 public void clearSuggestions() { 189 super.clearSuggestions(); 190 mResultsAdapter.setSuggestions(null); 191 } 192 193 @Override 194 public void setMaxPromotedResults(int maxPromoted) { 195 mResultsView.setLimitSuggestionsToViewHeight(false); 196 mResultsAdapter.setMaxPromoted(maxPromoted); 197 } 198 199 @Override 200 public void limitResultsToViewHeight() { 201 mResultsView.setLimitSuggestionsToViewHeight(true); 202 } 203 204 @Override 205 public void setSuggestionClickListener(SuggestionClickListener listener) { 206 super.setSuggestionClickListener(listener); 207 mResultsAdapter.setSuggestionClickListener(listener); 208 } 209 210 @Override 211 public void setSuggestions(Suggestions suggestions) { 212 super.setSuggestions(suggestions); 213 suggestions.acquire(); 214 mResultsAdapter.setSuggestions(suggestions); 215 } 216 217 @Override 218 protected void setCorpus(Corpus corpus) { 219 super.setCorpus(corpus); 220 mResultsAdapter.setPromoter(createResultsPromoter()); 221 } 222 223 @Override 224 protected Promoter createSuggestionsPromoter() { 225 return getQsbApplication().createWebPromoter(); 226 } 227 228 protected Promoter createResultsPromoter() { 229 Corpus corpus = getCorpus(); 230 if (corpus == null) { 231 return getQsbApplication().createResultsPromoter(); 232 } else { 233 return getQsbApplication().createSingleCorpusResultsPromoter(corpus); 234 } 235 } 236 237 protected void onResultsChanged() { 238 checkHideResultsHeader(); 239 } 240 241 @Override 242 protected void updateQueryTextView(boolean queryEmpty) { 243 super.updateQueryTextView(queryEmpty); 244 if (mSearchCloseButton == null) return; 245 246 if (queryEmpty) { 247 mSearchCloseButton.setImageResource(R.drawable.ic_clear_disabled); 248 } else { 249 mSearchCloseButton.setImageResource(R.drawable.ic_clear); 250 } 251 } 252 253 private void checkHideResultsHeader() { 254 if (mResultsHeader != null) { 255 if (!mResultsAdapter.isEmpty()) { 256 if (DBG) Log.d(TAG, "Results non-empty"); 257 mResultsHeader.setVisibility(VISIBLE); 258 } else { 259 if (DBG) Log.d(TAG, "Results empty"); 260 mResultsHeader.setVisibility(INVISIBLE); 261 } 262 } 263 } 264 265 @Override 266 public Corpus getSearchCorpus() { 267 return getWebCorpus(); 268 } 269 270 protected class ResultsObserver extends DataSetObserver { 271 @Override 272 public void onChanged() { 273 onResultsChanged(); 274 } 275 } 276 277} 278