SuggestionsView.java revision b5fc08b7f16a32d3865f44b7f26d8aaa5304a2ad
1/*
2 * Copyright (C) 2009 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.SuggestionPosition;
20
21import android.content.Context;
22import android.graphics.Rect;
23import android.util.AttributeSet;
24import android.util.Log;
25import android.view.MotionEvent;
26import android.view.View;
27import android.widget.AdapterView;
28import android.widget.ListView;
29
30/**
31 * Holds a list of suggestions.
32 */
33public class SuggestionsView extends ListView {
34
35    private static final boolean DBG = false;
36    private static final String TAG = "QSB.SuggestionsView";
37
38    private SuggestionClickListener mSuggestionClickListener;
39
40    private SuggestionSelectionListener mSuggestionSelectionListener;
41
42    private InteractionListener mInteractionListener;
43
44    public SuggestionsView(Context context, AttributeSet attrs) {
45        super(context, attrs);
46    }
47
48    @Override
49    public void onFinishInflate() {
50        super.onFinishInflate();
51        setOnItemClickListener(new ItemClickListener());
52        setOnItemLongClickListener(new ItemLongClickListener());
53        setOnItemSelectedListener(new ItemSelectedListener());
54    }
55
56    public void setSuggestionClickListener(SuggestionClickListener listener) {
57        mSuggestionClickListener = listener;
58    }
59
60    public void setSuggestionSelectionListener(SuggestionSelectionListener listener) {
61        mSuggestionSelectionListener = listener;
62    }
63
64    public void setInteractionListener(InteractionListener listener) {
65        mInteractionListener = listener;
66    }
67
68    /**
69     * Gets the position of the selected suggestion.
70     *
71     * @return A 0-based index, or {@code -1} if no suggestion is selected.
72     */
73    public int getSelectedPosition() {
74        return getSelectedItemPosition();
75    }
76
77    /**
78     * Gets the selected suggestion.
79     *
80     * @return {@code null} if no suggestion is selected.
81     */
82    public SuggestionPosition getSelectedSuggestion() {
83        return (SuggestionPosition) getSelectedItem();
84    }
85
86    @Override
87    public boolean onInterceptTouchEvent(MotionEvent event) {
88        if (event.getAction() == MotionEvent.ACTION_DOWN && mInteractionListener != null) {
89            mInteractionListener.onInteraction();
90        }
91        return super.onInterceptTouchEvent(event);
92    }
93
94    @Override
95    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
96        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
97        if (DBG) {
98            Log.d(TAG, "Suggestions focus change, gainFocus: " + gainFocus
99                    + ", selected=" + getSelectedItemPosition());
100        }
101        // In non-touch mode, ListView does not clear the list selection when
102        // the ListView loses focus. And when it regains focus, onItemSelected() never gets
103        // called if the new selected position is the same as the old. We work around that
104        // by firing extra selection events on focus changes in non-touch mode.
105        // This implementation can result in duplicate selection events when the old selected
106        // item is not the same as the new.
107        if (!isInTouchMode()) {
108            if (gainFocus) {
109                int position = getSelectedPosition();
110                if (position != INVALID_POSITION) {
111                    fireSuggestionSelected(position);
112                }
113            } else {
114                fireNothingSelected();
115            }
116        }
117    }
118
119    private void fireSuggestionSelected(int position) {
120        if (DBG) Log.d(TAG, "fireSuggestionSelected(" + position + ")");
121        if (mSuggestionSelectionListener != null) {
122            mSuggestionSelectionListener.onSuggestionSelected(position);
123        }
124    }
125
126    private void fireNothingSelected() {
127        if (DBG) Log.d(TAG, "fireNothingSelected()");
128        if (mSuggestionSelectionListener != null) {
129            mSuggestionSelectionListener.onNothingSelected();
130        }
131    }
132
133    public interface InteractionListener {
134        /**
135         * Called when the user interacts with this view.
136         */
137        void onInteraction();
138    }
139
140    private class ItemClickListener implements AdapterView.OnItemClickListener {
141        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
142            if (DBG) Log.d(TAG, "onItemClick(" + position + ")");
143            SuggestionView suggestionView = (SuggestionView) view;
144            if (mSuggestionClickListener != null) {
145                mSuggestionClickListener.onSuggestionClicked(position);
146            }
147        }
148    }
149
150    private class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
151        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
152            if (DBG) Log.d(TAG, "onItemLongClick(" + position + ")");
153            SuggestionView suggestionView = (SuggestionView) view;
154            if (mSuggestionClickListener != null) {
155                return mSuggestionClickListener.onSuggestionLongClicked(position);
156            }
157            return false;
158        }
159    }
160
161    private class ItemSelectedListener implements AdapterView.OnItemSelectedListener {
162        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
163            // Only fire suggestion selection events when the list has focus.
164            // This suppresses selection events caused by data set changes (as opposed
165            // to user action).
166            if (hasFocus()) {
167                fireSuggestionSelected(position);
168            } else {
169                if (DBG) Log.d(TAG, "Suppressed selection event for position " + position);
170            }
171        }
172
173        public void onNothingSelected(AdapterView<?> parent) {
174            fireNothingSelected();
175        }
176    }
177}
178