| 14792 |
manas |
1 |
/**
|
|
|
2 |
* Copyright 2010-present Facebook.
|
|
|
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.facebook.widget;
|
|
|
18 |
|
|
|
19 |
import android.app.Activity;
|
|
|
20 |
import android.content.Context;
|
|
|
21 |
import android.content.res.TypedArray;
|
|
|
22 |
import android.location.Location;
|
|
|
23 |
import android.os.Bundle;
|
|
|
24 |
import android.os.Handler;
|
|
|
25 |
import android.os.Looper;
|
|
|
26 |
import android.text.Editable;
|
|
|
27 |
import android.text.TextUtils;
|
|
|
28 |
import android.text.TextWatcher;
|
|
|
29 |
import android.util.AttributeSet;
|
|
|
30 |
import android.view.View;
|
|
|
31 |
import android.view.ViewGroup;
|
|
|
32 |
import android.view.inputmethod.InputMethodManager;
|
|
|
33 |
import android.widget.EditText;
|
|
|
34 |
import android.widget.ListView;
|
|
|
35 |
import com.facebook.*;
|
|
|
36 |
import com.facebook.android.R;
|
|
|
37 |
import com.facebook.internal.AnalyticsEvents;
|
|
|
38 |
import com.facebook.internal.Logger;
|
|
|
39 |
import com.facebook.internal.Utility;
|
|
|
40 |
import com.facebook.model.GraphPlace;
|
|
|
41 |
|
|
|
42 |
import java.util.*;
|
|
|
43 |
|
|
|
44 |
public class PlacePickerFragment extends PickerFragment<GraphPlace> {
|
|
|
45 |
/**
|
|
|
46 |
* The key for an int parameter in the fragment's Intent bundle to indicate the radius in meters around
|
|
|
47 |
* the center point to search. The default is 1000 meters.
|
|
|
48 |
*/
|
|
|
49 |
public static final String RADIUS_IN_METERS_BUNDLE_KEY = "com.facebook.widget.PlacePickerFragment.RadiusInMeters";
|
|
|
50 |
/**
|
|
|
51 |
* The key for an int parameter in the fragment's Intent bundle to indicate what how many results to
|
|
|
52 |
* return at a time. The default is 100 results.
|
|
|
53 |
*/
|
|
|
54 |
public static final String RESULTS_LIMIT_BUNDLE_KEY = "com.facebook.widget.PlacePickerFragment.ResultsLimit";
|
|
|
55 |
/**
|
|
|
56 |
* The key for a String parameter in the fragment's Intent bundle to indicate what search text should
|
|
|
57 |
* be sent to the service. The default is to have no search text.
|
|
|
58 |
*/
|
|
|
59 |
public static final String SEARCH_TEXT_BUNDLE_KEY = "com.facebook.widget.PlacePickerFragment.SearchText";
|
|
|
60 |
/**
|
|
|
61 |
* The key for a Location parameter in the fragment's Intent bundle to indicate what geographical
|
|
|
62 |
* location should be the center of the search.
|
|
|
63 |
*/
|
|
|
64 |
public static final String LOCATION_BUNDLE_KEY = "com.facebook.widget.PlacePickerFragment.Location";
|
|
|
65 |
/**
|
|
|
66 |
* The key for a boolean parameter in the fragment's Intent bundle to indicate that the fragment
|
|
|
67 |
* should display a search box and automatically update the search text as it changes.
|
|
|
68 |
*/
|
|
|
69 |
public static final String SHOW_SEARCH_BOX_BUNDLE_KEY = "com.facebook.widget.PlacePickerFragment.ShowSearchBox";
|
|
|
70 |
|
|
|
71 |
/**
|
|
|
72 |
* The default radius around the center point to search.
|
|
|
73 |
*/
|
|
|
74 |
public static final int DEFAULT_RADIUS_IN_METERS = 1000;
|
|
|
75 |
/**
|
|
|
76 |
* The default number of results to retrieve.
|
|
|
77 |
*/
|
|
|
78 |
public static final int DEFAULT_RESULTS_LIMIT = 100;
|
|
|
79 |
|
|
|
80 |
private static final int searchTextTimerDelayInMilliseconds = 2 * 1000;
|
|
|
81 |
|
|
|
82 |
private static final String ID = "id";
|
|
|
83 |
private static final String NAME = "name";
|
|
|
84 |
private static final String LOCATION = "location";
|
|
|
85 |
private static final String CATEGORY = "category";
|
|
|
86 |
private static final String WERE_HERE_COUNT = "were_here_count";
|
|
|
87 |
private static final String TAG = "PlacePickerFragment";
|
|
|
88 |
|
|
|
89 |
private Location location;
|
|
|
90 |
private int radiusInMeters = DEFAULT_RADIUS_IN_METERS;
|
|
|
91 |
private int resultsLimit = DEFAULT_RESULTS_LIMIT;
|
|
|
92 |
private String searchText;
|
|
|
93 |
private Timer searchTextTimer;
|
|
|
94 |
private boolean hasSearchTextChangedSinceLastQuery;
|
|
|
95 |
private boolean showSearchBox = true;
|
|
|
96 |
private EditText searchBox;
|
|
|
97 |
|
|
|
98 |
/**
|
|
|
99 |
* Default constructor. Creates a Fragment with all default properties.
|
|
|
100 |
*/
|
|
|
101 |
public PlacePickerFragment() {
|
|
|
102 |
this(null);
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
/**
|
|
|
106 |
* Constructor.
|
|
|
107 |
*
|
|
|
108 |
* @param args a Bundle that optionally contains one or more values containing additional
|
|
|
109 |
* configuration information for the Fragment.
|
|
|
110 |
*/
|
|
|
111 |
public PlacePickerFragment(Bundle args) {
|
|
|
112 |
super(GraphPlace.class, R.layout.com_facebook_placepickerfragment, args);
|
|
|
113 |
setPlacePickerSettingsFromBundle(args);
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
/**
|
|
|
117 |
* Gets the location to search around. Either the location or the search text (or both) must be specified.
|
|
|
118 |
*
|
|
|
119 |
* @return the Location to search around
|
|
|
120 |
*/
|
|
|
121 |
public Location getLocation() {
|
|
|
122 |
return location;
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
/**
|
|
|
126 |
* Sets the location to search around. Either the location or the search text (or both) must be specified.
|
|
|
127 |
*
|
|
|
128 |
* @param location the Location to search around
|
|
|
129 |
*/
|
|
|
130 |
public void setLocation(Location location) {
|
|
|
131 |
this.location = location;
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
/**
|
|
|
135 |
* Gets the radius in meters around the location to search.
|
|
|
136 |
*
|
|
|
137 |
* @return the radius in meters
|
|
|
138 |
*/
|
|
|
139 |
public int getRadiusInMeters() {
|
|
|
140 |
return radiusInMeters;
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
/**
|
|
|
144 |
* Sets the radius in meters around the location to search.
|
|
|
145 |
*
|
|
|
146 |
* @param radiusInMeters the radius in meters
|
|
|
147 |
*/
|
|
|
148 |
public void setRadiusInMeters(int radiusInMeters) {
|
|
|
149 |
this.radiusInMeters = radiusInMeters;
|
|
|
150 |
}
|
|
|
151 |
|
|
|
152 |
/**
|
|
|
153 |
* Gets the number of results to retrieve.
|
|
|
154 |
*
|
|
|
155 |
* @return the number of results to retrieve
|
|
|
156 |
*/
|
|
|
157 |
public int getResultsLimit() {
|
|
|
158 |
return resultsLimit;
|
|
|
159 |
}
|
|
|
160 |
|
|
|
161 |
/**
|
|
|
162 |
* Sets the number of results to retrieve.
|
|
|
163 |
*
|
|
|
164 |
* @param resultsLimit the number of results to retrieve
|
|
|
165 |
*/
|
|
|
166 |
public void setResultsLimit(int resultsLimit) {
|
|
|
167 |
this.resultsLimit = resultsLimit;
|
|
|
168 |
}
|
|
|
169 |
|
|
|
170 |
/**
|
|
|
171 |
* Gets the search text (e.g., category, name) to search for. Either the location or the search
|
|
|
172 |
* text (or both) must be specified.
|
|
|
173 |
*
|
|
|
174 |
* @return the search text
|
|
|
175 |
*/
|
|
|
176 |
public String getSearchText() {
|
|
|
177 |
return searchText;
|
|
|
178 |
}
|
|
|
179 |
|
|
|
180 |
/**
|
|
|
181 |
* Sets the search text (e.g., category, name) to search for. Either the location or the search
|
|
|
182 |
* text (or both) must be specified. If a search box is displayed, this will update its contents
|
|
|
183 |
* to the specified text.
|
|
|
184 |
*
|
|
|
185 |
* @param searchText the search text
|
|
|
186 |
*/
|
|
|
187 |
public void setSearchText(String searchText) {
|
|
|
188 |
if (TextUtils.isEmpty(searchText)) {
|
|
|
189 |
searchText = null;
|
|
|
190 |
}
|
|
|
191 |
this.searchText = searchText;
|
|
|
192 |
if (this.searchBox != null) {
|
|
|
193 |
this.searchBox.setText(searchText);
|
|
|
194 |
}
|
|
|
195 |
}
|
|
|
196 |
|
|
|
197 |
/**
|
|
|
198 |
* Sets the search text and reloads the data in the control. This is used to provide search-box
|
|
|
199 |
* functionality where the user may be typing or editing text rapidly. It uses a timer to avoid repeated
|
|
|
200 |
* requerying, preferring to wait until the user pauses typing to refresh the data. Note that this
|
|
|
201 |
* method will NOT update the text in the search box, if any, as it is intended to be called as a result
|
|
|
202 |
* of changes to the search box (and is public to enable applications to provide their own search box
|
|
|
203 |
* UI instead of the default one).
|
|
|
204 |
*
|
|
|
205 |
* @param searchText the search text
|
|
|
206 |
* @param forceReloadEventIfSameText if true, will reload even if the search text has not changed; if false,
|
|
|
207 |
* identical search text will not force a reload
|
|
|
208 |
*/
|
|
|
209 |
public void onSearchBoxTextChanged(String searchText, boolean forceReloadEventIfSameText) {
|
|
|
210 |
if (!forceReloadEventIfSameText && Utility.stringsEqualOrEmpty(this.searchText, searchText)) {
|
|
|
211 |
return;
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
if (TextUtils.isEmpty(searchText)) {
|
|
|
215 |
searchText = null;
|
|
|
216 |
}
|
|
|
217 |
this.searchText = searchText;
|
|
|
218 |
|
|
|
219 |
// If search text is being set in response to user input, it is wasteful to send a new request
|
|
|
220 |
// with every keystroke. Send a request the first time the search text is set, then set up a 2-second timer
|
|
|
221 |
// and send whatever changes the user has made since then. (If nothing has changed
|
|
|
222 |
// in 2 seconds, we reset so the next change will cause an immediate re-query.)
|
|
|
223 |
hasSearchTextChangedSinceLastQuery = true;
|
|
|
224 |
if (searchTextTimer == null) {
|
|
|
225 |
searchTextTimer = createSearchTextTimer();
|
|
|
226 |
}
|
|
|
227 |
}
|
|
|
228 |
|
|
|
229 |
/**
|
|
|
230 |
* Gets the currently-selected place.
|
|
|
231 |
*
|
|
|
232 |
* @return the currently-selected place, or null if there is none
|
|
|
233 |
*/
|
|
|
234 |
public GraphPlace getSelection() {
|
|
|
235 |
Collection<GraphPlace> selection = getSelectedGraphObjects();
|
|
|
236 |
return (selection != null && !selection.isEmpty()) ? selection.iterator().next() : null;
|
|
|
237 |
}
|
|
|
238 |
|
|
|
239 |
public void setSettingsFromBundle(Bundle inState) {
|
|
|
240 |
super.setSettingsFromBundle(inState);
|
|
|
241 |
setPlacePickerSettingsFromBundle(inState);
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
@Override
|
|
|
245 |
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
|
|
|
246 |
super.onInflate(activity, attrs, savedInstanceState);
|
|
|
247 |
TypedArray a = activity.obtainStyledAttributes(attrs, R.styleable.com_facebook_place_picker_fragment);
|
|
|
248 |
|
|
|
249 |
setRadiusInMeters(a.getInt(R.styleable.com_facebook_place_picker_fragment_radius_in_meters, radiusInMeters));
|
|
|
250 |
setResultsLimit(a.getInt(R.styleable.com_facebook_place_picker_fragment_results_limit, resultsLimit));
|
|
|
251 |
if (a.hasValue(R.styleable.com_facebook_place_picker_fragment_results_limit)) {
|
|
|
252 |
setSearchText(a.getString(R.styleable.com_facebook_place_picker_fragment_search_text));
|
|
|
253 |
}
|
|
|
254 |
showSearchBox = a.getBoolean(R.styleable.com_facebook_place_picker_fragment_show_search_box, showSearchBox);
|
|
|
255 |
|
|
|
256 |
a.recycle();
|
|
|
257 |
}
|
|
|
258 |
|
|
|
259 |
@Override
|
|
|
260 |
void setupViews(ViewGroup view) {
|
|
|
261 |
if (showSearchBox) {
|
|
|
262 |
ListView listView = (ListView) view.findViewById(R.id.com_facebook_picker_list_view);
|
|
|
263 |
|
|
|
264 |
View searchHeaderView = getActivity().getLayoutInflater().inflate(
|
|
|
265 |
R.layout.com_facebook_picker_search_box, listView, false);
|
|
|
266 |
|
|
|
267 |
listView.addHeaderView(searchHeaderView, null, false);
|
|
|
268 |
|
|
|
269 |
searchBox = (EditText) view.findViewById(R.id.com_facebook_picker_search_text);
|
|
|
270 |
|
|
|
271 |
searchBox.addTextChangedListener(new SearchTextWatcher());
|
|
|
272 |
if (!TextUtils.isEmpty(searchText)) {
|
|
|
273 |
searchBox.setText(searchText);
|
|
|
274 |
}
|
|
|
275 |
}
|
|
|
276 |
}
|
|
|
277 |
|
|
|
278 |
@Override
|
|
|
279 |
public void onAttach(Activity activity) {
|
|
|
280 |
super.onAttach(activity);
|
|
|
281 |
|
|
|
282 |
if (searchBox != null) {
|
|
|
283 |
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
284 |
imm.showSoftInput(searchBox, InputMethodManager.SHOW_IMPLICIT);
|
|
|
285 |
}
|
|
|
286 |
}
|
|
|
287 |
|
|
|
288 |
@Override
|
|
|
289 |
public void onDetach() {
|
|
|
290 |
super.onDetach();
|
|
|
291 |
|
|
|
292 |
if (searchBox != null) {
|
|
|
293 |
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
294 |
imm.hideSoftInputFromWindow(searchBox.getWindowToken(), 0);
|
|
|
295 |
}
|
|
|
296 |
}
|
|
|
297 |
|
|
|
298 |
void saveSettingsToBundle(Bundle outState) {
|
|
|
299 |
super.saveSettingsToBundle(outState);
|
|
|
300 |
|
|
|
301 |
outState.putInt(RADIUS_IN_METERS_BUNDLE_KEY, radiusInMeters);
|
|
|
302 |
outState.putInt(RESULTS_LIMIT_BUNDLE_KEY, resultsLimit);
|
|
|
303 |
outState.putString(SEARCH_TEXT_BUNDLE_KEY, searchText);
|
|
|
304 |
outState.putParcelable(LOCATION_BUNDLE_KEY, location);
|
|
|
305 |
outState.putBoolean(SHOW_SEARCH_BOX_BUNDLE_KEY, showSearchBox);
|
|
|
306 |
}
|
|
|
307 |
|
|
|
308 |
@Override
|
|
|
309 |
void onLoadingData() {
|
|
|
310 |
hasSearchTextChangedSinceLastQuery = false;
|
|
|
311 |
}
|
|
|
312 |
|
|
|
313 |
@Override
|
|
|
314 |
Request getRequestForLoadData(Session session) {
|
|
|
315 |
return createRequest(location, radiusInMeters, resultsLimit, searchText, extraFields, session);
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
@Override
|
|
|
319 |
String getDefaultTitleText() {
|
|
|
320 |
return getString(R.string.com_facebook_nearby);
|
|
|
321 |
}
|
|
|
322 |
|
|
|
323 |
@Override
|
|
|
324 |
void logAppEvents(boolean doneButtonClicked) {
|
|
|
325 |
AppEventsLogger logger = AppEventsLogger.newLogger(this.getActivity(), getSession());
|
|
|
326 |
Bundle parameters = new Bundle();
|
|
|
327 |
|
|
|
328 |
// If Done was clicked, we know this completed successfully. If not, we don't know (caller might have
|
|
|
329 |
// dismissed us in response to selection changing, or user might have hit back button). Either way
|
|
|
330 |
// we'll log the number of selections.
|
|
|
331 |
String outcome = doneButtonClicked ? AnalyticsEvents.PARAMETER_DIALOG_OUTCOME_VALUE_COMPLETED :
|
|
|
332 |
AnalyticsEvents.PARAMETER_DIALOG_OUTCOME_VALUE_UNKNOWN;
|
|
|
333 |
parameters.putString(AnalyticsEvents.PARAMETER_DIALOG_OUTCOME, outcome);
|
|
|
334 |
parameters.putInt("num_places_picked", (getSelection() != null) ? 1 : 0);
|
|
|
335 |
|
|
|
336 |
logger.logSdkEvent(AnalyticsEvents.EVENT_PLACE_PICKER_USAGE, null, parameters);
|
|
|
337 |
}
|
|
|
338 |
|
|
|
339 |
@Override
|
|
|
340 |
PickerFragmentAdapter<GraphPlace> createAdapter() {
|
|
|
341 |
PickerFragmentAdapter<GraphPlace> adapter = new PickerFragmentAdapter<GraphPlace>(
|
|
|
342 |
this.getActivity()) {
|
|
|
343 |
@Override
|
|
|
344 |
protected CharSequence getSubTitleOfGraphObject(GraphPlace graphObject) {
|
|
|
345 |
String category = graphObject.getCategory();
|
|
|
346 |
Integer wereHereCount = (Integer) graphObject.getProperty(WERE_HERE_COUNT);
|
|
|
347 |
|
|
|
348 |
String result = null;
|
|
|
349 |
if (category != null && wereHereCount != null) {
|
|
|
350 |
result = getString(R.string.com_facebook_placepicker_subtitle_format, category, wereHereCount);
|
|
|
351 |
} else if (category == null && wereHereCount != null) {
|
|
|
352 |
result = getString(R.string.com_facebook_placepicker_subtitle_were_here_only_format, wereHereCount);
|
|
|
353 |
} else if (category != null && wereHereCount == null) {
|
|
|
354 |
result = getString(R.string.com_facebook_placepicker_subtitle_catetory_only_format, category);
|
|
|
355 |
}
|
|
|
356 |
return result;
|
|
|
357 |
}
|
|
|
358 |
|
|
|
359 |
@Override
|
|
|
360 |
protected int getGraphObjectRowLayoutId(GraphPlace graphObject) {
|
|
|
361 |
return R.layout.com_facebook_placepickerfragment_list_row;
|
|
|
362 |
}
|
|
|
363 |
|
|
|
364 |
@Override
|
|
|
365 |
protected int getDefaultPicture() {
|
|
|
366 |
return R.drawable.com_facebook_place_default_icon;
|
|
|
367 |
}
|
|
|
368 |
|
|
|
369 |
};
|
|
|
370 |
adapter.setShowCheckbox(false);
|
|
|
371 |
adapter.setShowPicture(getShowPictures());
|
|
|
372 |
return adapter;
|
|
|
373 |
}
|
|
|
374 |
|
|
|
375 |
@Override
|
|
|
376 |
LoadingStrategy createLoadingStrategy() {
|
|
|
377 |
return new AsNeededLoadingStrategy();
|
|
|
378 |
}
|
|
|
379 |
|
|
|
380 |
@Override
|
|
|
381 |
SelectionStrategy createSelectionStrategy() {
|
|
|
382 |
return new SingleSelectionStrategy();
|
|
|
383 |
}
|
|
|
384 |
|
|
|
385 |
private Request createRequest(Location location, int radiusInMeters, int resultsLimit, String searchText,
|
|
|
386 |
Set<String> extraFields,
|
|
|
387 |
Session session) {
|
|
|
388 |
Request request = Request.newPlacesSearchRequest(session, location, radiusInMeters, resultsLimit, searchText,
|
|
|
389 |
null);
|
|
|
390 |
|
|
|
391 |
Set<String> fields = new HashSet<String>(extraFields);
|
|
|
392 |
String[] requiredFields = new String[]{
|
|
|
393 |
ID,
|
|
|
394 |
NAME,
|
|
|
395 |
LOCATION,
|
|
|
396 |
CATEGORY,
|
|
|
397 |
WERE_HERE_COUNT
|
|
|
398 |
};
|
|
|
399 |
fields.addAll(Arrays.asList(requiredFields));
|
|
|
400 |
|
|
|
401 |
String pictureField = adapter.getPictureFieldSpecifier();
|
|
|
402 |
if (pictureField != null) {
|
|
|
403 |
fields.add(pictureField);
|
|
|
404 |
}
|
|
|
405 |
|
|
|
406 |
Bundle parameters = request.getParameters();
|
|
|
407 |
parameters.putString("fields", TextUtils.join(",", fields));
|
|
|
408 |
request.setParameters(parameters);
|
|
|
409 |
|
|
|
410 |
return request;
|
|
|
411 |
}
|
|
|
412 |
|
|
|
413 |
private void setPlacePickerSettingsFromBundle(Bundle inState) {
|
|
|
414 |
// We do this in a separate non-overridable method so it is safe to call from the constructor.
|
|
|
415 |
if (inState != null) {
|
|
|
416 |
setRadiusInMeters(inState.getInt(RADIUS_IN_METERS_BUNDLE_KEY, radiusInMeters));
|
|
|
417 |
setResultsLimit(inState.getInt(RESULTS_LIMIT_BUNDLE_KEY, resultsLimit));
|
|
|
418 |
if (inState.containsKey(SEARCH_TEXT_BUNDLE_KEY)) {
|
|
|
419 |
setSearchText(inState.getString(SEARCH_TEXT_BUNDLE_KEY));
|
|
|
420 |
}
|
|
|
421 |
if (inState.containsKey(LOCATION_BUNDLE_KEY)) {
|
|
|
422 |
Location location = inState.getParcelable(LOCATION_BUNDLE_KEY);
|
|
|
423 |
setLocation(location);
|
|
|
424 |
}
|
|
|
425 |
showSearchBox = inState.getBoolean(SHOW_SEARCH_BOX_BUNDLE_KEY, showSearchBox);
|
|
|
426 |
}
|
|
|
427 |
}
|
|
|
428 |
|
|
|
429 |
private Timer createSearchTextTimer() {
|
|
|
430 |
Timer timer = new Timer();
|
|
|
431 |
timer.schedule(new TimerTask() {
|
|
|
432 |
@Override
|
|
|
433 |
public void run() {
|
|
|
434 |
onSearchTextTimerTriggered();
|
|
|
435 |
}
|
|
|
436 |
}, 0, searchTextTimerDelayInMilliseconds);
|
|
|
437 |
|
|
|
438 |
return timer;
|
|
|
439 |
}
|
|
|
440 |
|
|
|
441 |
private void onSearchTextTimerTriggered() {
|
|
|
442 |
if (hasSearchTextChangedSinceLastQuery) {
|
|
|
443 |
Handler handler = new Handler(Looper.getMainLooper());
|
|
|
444 |
handler.post(new Runnable() {
|
|
|
445 |
@Override
|
|
|
446 |
public void run() {
|
|
|
447 |
FacebookException error = null;
|
|
|
448 |
try {
|
|
|
449 |
loadData(true);
|
|
|
450 |
} catch (FacebookException fe) {
|
|
|
451 |
error = fe;
|
|
|
452 |
} catch (Exception e) {
|
|
|
453 |
error = new FacebookException(e);
|
|
|
454 |
} finally {
|
|
|
455 |
if (error != null) {
|
|
|
456 |
OnErrorListener onErrorListener = getOnErrorListener();
|
|
|
457 |
if (onErrorListener != null) {
|
|
|
458 |
onErrorListener.onError(PlacePickerFragment.this, error);
|
|
|
459 |
} else {
|
|
|
460 |
Logger.log(LoggingBehavior.REQUESTS, TAG, "Error loading data : %s", error);
|
|
|
461 |
}
|
|
|
462 |
}
|
|
|
463 |
}
|
|
|
464 |
}
|
|
|
465 |
});
|
|
|
466 |
} else {
|
|
|
467 |
// Nothing has changed in 2 seconds. Invalidate and forget about this timer.
|
|
|
468 |
// Next time the user types, we will fire a query immediately again.
|
|
|
469 |
searchTextTimer.cancel();
|
|
|
470 |
searchTextTimer = null;
|
|
|
471 |
}
|
|
|
472 |
}
|
|
|
473 |
|
|
|
474 |
private class AsNeededLoadingStrategy extends LoadingStrategy {
|
|
|
475 |
@Override
|
|
|
476 |
public void attach(GraphObjectAdapter<GraphPlace> adapter) {
|
|
|
477 |
super.attach(adapter);
|
|
|
478 |
|
|
|
479 |
this.adapter.setDataNeededListener(new GraphObjectAdapter.DataNeededListener() {
|
|
|
480 |
@Override
|
|
|
481 |
public void onDataNeeded() {
|
|
|
482 |
// Do nothing if we are currently loading data . We will get notified again when that load finishes if the adapter still
|
|
|
483 |
// needs more data. Otherwise, follow the next link.
|
|
|
484 |
if (!loader.isLoading()) {
|
|
|
485 |
loader.followNextLink();
|
|
|
486 |
}
|
|
|
487 |
}
|
|
|
488 |
});
|
|
|
489 |
}
|
|
|
490 |
|
|
|
491 |
@Override
|
|
|
492 |
protected void onLoadFinished(GraphObjectPagingLoader<GraphPlace> loader,
|
|
|
493 |
SimpleGraphObjectCursor<GraphPlace> data) {
|
|
|
494 |
super.onLoadFinished(loader, data);
|
|
|
495 |
|
|
|
496 |
// We could be called in this state if we are clearing data or if we are being re-attached
|
|
|
497 |
// in the middle of a query.
|
|
|
498 |
if (data == null || loader.isLoading()) {
|
|
|
499 |
return;
|
|
|
500 |
}
|
|
|
501 |
|
|
|
502 |
hideActivityCircle();
|
|
|
503 |
|
|
|
504 |
if (data.isFromCache()) {
|
|
|
505 |
// Only the first page can be cached, since all subsequent pages will be round-tripped. Force
|
|
|
506 |
// a refresh of the first page before we allow paging to begin. If the first page produced
|
|
|
507 |
// no data, launch the refresh immediately, otherwise schedule it for later.
|
|
|
508 |
loader.refreshOriginalRequest(data.areMoreObjectsAvailable() ? CACHED_RESULT_REFRESH_DELAY : 0);
|
|
|
509 |
}
|
|
|
510 |
}
|
|
|
511 |
}
|
|
|
512 |
|
|
|
513 |
private class SearchTextWatcher implements TextWatcher {
|
|
|
514 |
|
|
|
515 |
@Override
|
|
|
516 |
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
|
517 |
}
|
|
|
518 |
|
|
|
519 |
@Override
|
|
|
520 |
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
|
521 |
onSearchBoxTextChanged(s.toString(), false);
|
|
|
522 |
}
|
|
|
523 |
|
|
|
524 |
@Override
|
|
|
525 |
public void afterTextChanged(Editable s) {
|
|
|
526 |
}
|
|
|
527 |
}
|
|
|
528 |
}
|