I am using the Google places Autocomplete API. My application has an Autocomplete text view. Everything is working fine as I followed the example here .
Only issue being I am setting LatLng bounds to that of Mountain View.
private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
My GoogleApiClient
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Places.GEO_DATA_API)
.build();
When I try to enter an New Orleans address, I have to type a lot which is not a good experience for any user that is out of CA. Is there a better way to set the LatLng bounds depending upon the current location without asking for Location permission or precise location position. I am assuming this is not a limitation of the Places API but just my limited knowledge.
Thanks in advance.
From the place_id you got, query Place Details something like https://maps.googleapis.com/maps/api/place/details/json?placeid={placeid}&key={key} and you can get the lat and lng from result. geometry. location JSON.
Google Places is Google's listing for local business search results. Google Places appears at the very top of the Google search results when a user is looking for local information.
Unfortunately no, you will need the location permission since the permission you choose in your manifest determines the accuracy of the location returned by the Google API Client. I would suggest using ACCESS_COARSE_LOCATION which is accurate within 1 city block. Here is how I dynamically got the user's location and made a bound of approx. 5 mile radius around their location.
public class PlacesSearchActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener,GoogleApiClient.ConnectionCallbacks, LocationListener {
private String TAG = this.toString();
protected GoogleApiClient mGoogleApiClient;
private AutoCompleteTextView mAutocompleteView;
private PlaceAutocompleteAdapter mAdapter;
private LocationRequest mLocationRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_places_search);
// Construct a GoogleApiClient for the {@link Places#GEO_DATA_API} using AutoManage
// functionality, which automatically sets up the API client to handle Activity lifecycle
// events. If your activity does not extend FragmentActivity, make sure to call connect()
// and disconnect() explicitly.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.enableAutoManage(this, 0 /* clientId */, this)
.addApi(Places.GEO_DATA_API)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_LOW_POWER)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
// Retrieve the AutoCompleteTextView that will display Place suggestions.
mAutocompleteView = (AutoCompleteTextView)findViewById(R.id.autocomplete_places);
// Register a listener that receives callbacks when a suggestion has been selected
mAutocompleteView.setOnItemClickListener(mAutocompleteClickListener);
}
private void setBounds(Location location, int mDistanceInMeters ){
double latRadian = Math.toRadians(location.getLatitude());
double degLatKm = 110.574235;
double degLongKm = 110.572833 * Math.cos(latRadian);
double deltaLat = mDistanceInMeters / 1000.0 / degLatKm;
double deltaLong = mDistanceInMeters / 1000.0 / degLongKm;
double minLat = location.getLatitude() - deltaLat;
double minLong = location.getLongitude() - deltaLong;
double maxLat = location.getLatitude() + deltaLat;
double maxLong = location.getLongitude() + deltaLong;
Log.d(TAG,"Min: "+Double.toString(minLat)+","+Double.toString(minLong));
Log.d(TAG,"Max: "+Double.toString(maxLat)+","+Double.toString(maxLong));
// Set up the adapter that will retrieve suggestions from the Places Geo Data API that cover
// the entire world.
mAdapter = new PlaceAutocompleteAdapter(this, android.R.layout.simple_list_item_1,
mGoogleApiClient, new LatLngBounds(new LatLng(minLat, minLong), new LatLng(maxLat, maxLong)), null);
mAutocompleteView.setAdapter(mAdapter);
}
/**
* Listener that handles selections from suggestions from the AutoCompleteTextView that
* displays Place suggestions.
* Gets the place id of the selected item and issues a request to the Places Geo Data API
* to retrieve more details about the place.
*
* @see com.google.android.gms.location.places.GeoDataApi#getPlaceById(com.google.android.gms.common.api.GoogleApiClient,
* String...)
*/
private AdapterView.OnItemClickListener mAutocompleteClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
/*
Retrieve the place ID of the selected item from the Adapter.
The adapter stores each Place suggestion in a PlaceAutocomplete object from which we
read the place ID.
*/
final PlaceAutocompleteAdapter.PlaceAutocomplete item = mAdapter.getItem(position);
final String placeId = String.valueOf(item.placeId);
Log.i(TAG, "Autocomplete item selected: " + item.description);
/*
Issue a request to the Places Geo Data API to retrieve a Place object with additional
details about the place.
*/
PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi
.getPlaceById(mGoogleApiClient, placeId);
placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
Toast.makeText(getApplicationContext(), "Clicked: " + item.description,
Toast.LENGTH_SHORT).show();
Log.i(TAG, "Called getPlaceById to get Place details for " + item.placeId);
}
};
/**
* Callback for results from a Places Geo Data API query that shows the first place result in
* the details view on screen.
*/
private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback
= new ResultCallback<PlaceBuffer>() {
@Override
public void onResult(PlaceBuffer places) {
if (!places.getStatus().isSuccess()) {
// Request did not complete successfully
Log.e(TAG, "Place query did not complete. Error: " + places.getStatus().toString());
places.release();
return;
}
// Get the Place object from the buffer.
final Place place = places.get(0);
Log.i(TAG, "Place details received: " + place.getName());
places.release();
}
};
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
// TODO(Developer): Check error code and notify the user of error state and resolution.
Toast.makeText(this,"Could not connect to Google API Client: Error " + connectionResult.getErrorCode(),Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationChanged(Location location) {
setBounds(location,5500);
}
@Override
public void onConnected(Bundle bundle) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} else {
setBounds(location,5500);
}
}
@Override
public void onConnectionSuspended(int i) {
}
}
If anyone is looking for an answer @opt05 is not totally correct, if we implement com.google.maps.android:android-maps-utils
we can just use SphericalUtil.ComputeOffset
to get a
north corner
and a
south corner
and set bounds by an autocompletefilter
.
a complete example is :
LatLng center = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
LatLng northSide = SphericalUtil.computeOffset(center, 50000, 0);
LatLng southSide = SphericalUtil.computeOffset(center, 50000, 180);
LatLngBounds bounds = LatLngBounds.builder()
.include(northSide)
.include(southSide)
.build();
placeLocation.setBoundsBias(bounds);
placeLocation.setFilter(typeFilter);
placeDestination.setBoundsBias(bounds);
placeDestination.setFilter(typeFilter);
here placeLocation
is a AutoCompleteFragment
and northside and southside method computeOffset
is
(center where you currently are or whatever position you would like to limit"Put a radius on" in your case its moutainview)
(50,000 is the distance in metes)
(0 is for north, 90 is east, 180 south, 270 west).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With