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