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
18fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport com.android.quicksearchbox.Suggestion;
19fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport com.android.quicksearchbox.SuggestionCursor;
20fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport com.android.quicksearchbox.SuggestionPosition;
21fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport com.android.quicksearchbox.Suggestions;
22fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
23fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.database.DataSetObserver;
24fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.util.Log;
25fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.view.View;
26fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.view.View.OnFocusChangeListener;
27fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.view.ViewGroup;
28fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
29fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport java.util.HashMap;
30fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
31fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood/**
32fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood * Base class for suggestions adapters. The templated class A is the list adapter class.
33fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood */
34fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodpublic abstract class SuggestionsAdapterBase<A> implements SuggestionsAdapter<A> {
35fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
36fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private static final boolean DBG = false;
37fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private static final String TAG = "QSB.SuggestionsAdapter";
38fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
39fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private DataSetObserver mDataSetObserver;
40fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
41ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    private SuggestionCursor mCurrentSuggestions;
42fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private final HashMap<String, Integer> mViewTypeMap;
4377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    private final SuggestionViewFactory mViewFactory;
44fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
45fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private Suggestions mSuggestions;
46fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
47fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private SuggestionClickListener mSuggestionClickListener;
48fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private OnFocusChangeListener mOnFocusChangeListener;
49fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
50fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private boolean mClosed = false;
51fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
5277909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    protected SuggestionsAdapterBase(SuggestionViewFactory viewFactory) {
5377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        mViewFactory = viewFactory;
54fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mViewTypeMap = new HashMap<String, Integer>();
5577909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        for (String viewType : mViewFactory.getSuggestionViewTypes()) {
5677909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert            if (!mViewTypeMap.containsKey(viewType)) {
5777909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert                mViewTypeMap.put(viewType, mViewTypeMap.size());
5877909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert            }
5977909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        }
60fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
61fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
62ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
637a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public abstract boolean isEmpty();
647a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
65fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public boolean isClosed() {
66fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mClosed;
67fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
68fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
69fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public void close() {
70fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        setSuggestions(null);
71fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mClosed = true;
72fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
73fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
74ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
75fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public void setSuggestionClickListener(SuggestionClickListener listener) {
76fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mSuggestionClickListener = listener;
77fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
78fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
79ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
80fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public void setOnFocusChangeListener(OnFocusChangeListener l) {
81fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mOnFocusChangeListener = l;
82fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
83fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
84ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
85fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public void setSuggestions(Suggestions suggestions) {
86fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mSuggestions == suggestions) {
87fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            return;
88fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
89fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mClosed) {
90fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            if (suggestions != null) {
91fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                suggestions.release();
92fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            }
93fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            return;
94fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
95fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mDataSetObserver == null) {
96fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            mDataSetObserver = new MySuggestionsObserver();
97fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
98fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        // TODO: delay the change if there are no suggestions for the currently visible tab.
99fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mSuggestions != null) {
100fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            mSuggestions.unregisterDataSetObserver(mDataSetObserver);
101fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            mSuggestions.release();
102fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
103fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mSuggestions = suggestions;
104fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mSuggestions != null) {
105fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            mSuggestions.registerDataSetObserver(mDataSetObserver);
106fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
107fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        onSuggestionsChanged();
108fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
109fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
110ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
111fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public Suggestions getSuggestions() {
112fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mSuggestions;
113fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
114fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
115ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
1167a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public abstract SuggestionPosition getSuggestion(long suggestionId);
1177a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood
118ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    protected int getCount() {
119ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        return mCurrentSuggestions == null ? 0 : mCurrentSuggestions.getCount();
120fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
121fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
122ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    protected SuggestionPosition getSuggestion(int position) {
123ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        if (mCurrentSuggestions == null) return null;
124ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        return new SuggestionPosition(mCurrentSuggestions, position);
125fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
126fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
127fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected int getViewTypeCount() {
128fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mViewTypeMap.size();
129fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
130fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
131fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private String suggestionViewType(Suggestion suggestion) {
13277909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        String viewType = mViewFactory.getViewType(suggestion);
133fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (!mViewTypeMap.containsKey(viewType)) {
134fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            throw new IllegalStateException("Unknown viewType " + viewType);
135fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
136fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return viewType;
137fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
138fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
139fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected int getSuggestionViewType(SuggestionCursor cursor, int position) {
140fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (cursor == null) {
141fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            return 0;
142fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
143fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        cursor.moveTo(position);
144fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mViewTypeMap.get(suggestionViewType(cursor));
145fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
146fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
147fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected int getSuggestionViewTypeCount() {
148fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mViewTypeMap.size();
149fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
150fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
1517a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    protected View getView(SuggestionCursor suggestions, int position, long suggestionId,
152fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            View convertView, ViewGroup parent) {
153fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        suggestions.moveTo(position);
15477909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        View v = mViewFactory.getView(suggestions, suggestions.getUserQuery(), convertView, parent);
155fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (v instanceof SuggestionView) {
1567a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            ((SuggestionView) v).bindAdapter(this, suggestionId);
157fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        } else {
1587a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            SuggestionViewClickListener l = new SuggestionViewClickListener(suggestionId);
159fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            v.setOnClickListener(l);
160fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
161fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
162fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (mOnFocusChangeListener != null) {
163fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            v.setOnFocusChangeListener(mOnFocusChangeListener);
164fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
165fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return v;
166fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
167fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
168fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected void onSuggestionsChanged() {
169fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (DBG) Log.d(TAG, "onSuggestionsChanged(" + mSuggestions + ")");
170ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        SuggestionCursor cursor = null;
171ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        if (mSuggestions != null) {
172ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            cursor = mSuggestions.getResult();
173ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        }
174ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        changeSuggestions(cursor);
175fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
176fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
177ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    public SuggestionCursor getCurrentSuggestions() {
178ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        return mCurrentSuggestions;
179fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
180fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
181fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    /**
182fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood     * Replace the cursor.
183fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood     *
184fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood     * This does not close the old cursor. Instead, all the cursors are closed in
185fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood     * {@link #setSuggestions(Suggestions)}.
186fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood     */
187ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    private void changeSuggestions(SuggestionCursor newCursor) {
188fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        if (DBG) {
189fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            Log.d(TAG, "changeCursor(" + newCursor + ") count=" +
190fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                    (newCursor == null ? 0 : newCursor.getCount()));
191fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
192ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        if (newCursor == mCurrentSuggestions) {
193fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            if (newCursor != null) {
194fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                // Shortcuts may have changed without the cursor changing.
195fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood                notifyDataSetChanged();
196fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            }
197fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            return;
198fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
199ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        mCurrentSuggestions = newCursor;
200ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        if (mCurrentSuggestions != null) {
201fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            notifyDataSetChanged();
202fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        } else {
203fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            notifyDataSetInvalidated();
204fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
205fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
206fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
207ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
2087a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public void onSuggestionClicked(long suggestionId) {
209bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood        if (mClosed) {
210bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood            Log.w(TAG, "onSuggestionClicked after close");
211bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood        } else if (mSuggestionClickListener != null) {
2127a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            mSuggestionClickListener.onSuggestionClicked(this, suggestionId);
213fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
214fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
215fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
216ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
2177a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    public void onSuggestionQueryRefineClicked(long suggestionId) {
218bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood        if (mClosed) {
219bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood            Log.w(TAG, "onSuggestionQueryRefineClicked after close");
220bb57ae79a795983f048d1f43aa6dfc538906bc6aMathew Inwood        } else if (mSuggestionClickListener != null) {
2217a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            mSuggestionClickListener.onSuggestionQueryRefineClicked(this, suggestionId);
222fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
223fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
224fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
225ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
226fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public abstract A getListAdapter();
227fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
228fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected abstract void notifyDataSetInvalidated();
229fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
230fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected abstract void notifyDataSetChanged();
231fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
232fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private class MySuggestionsObserver extends DataSetObserver {
233fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        @Override
234fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public void onChanged() {
235fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood            onSuggestionsChanged();
236fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
237fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
238fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
239fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    private class SuggestionViewClickListener implements View.OnClickListener {
2407a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        private final long mSuggestionId;
2417a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood        public SuggestionViewClickListener(long suggestionId) {
2427a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            mSuggestionId = suggestionId;
243fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
244ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        @Override
245fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        public void onClick(View v) {
2467a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood            onSuggestionClicked(mSuggestionId);
247fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        }
248fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    }
249fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood
250fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood}
251