Felipe Caldas Felipe Caldas - 6 days ago 5
Android Question

How to check if position if valid in StreetView in Android

I have an app that is randomly generating positions in a GoogleMaps based on a defined boundary. So I first generate a random LatLng and then I verify if this point is inside my boundary. If it is, it's valid.

Builder builder = new LatLngBounds.Builder();

double antartica[] = {-62.5670958528642, -59.92767333984375, -62.584805850293485, -59.98260498046875, -62.61450963659083};
for (int i = 0; i < antartica.length; i++) {
builder.include(new LatLng(antartica[i],antartica[++i]));
}
pAntarctica = builder.build();

LatLng point = generateRandomPosition();
if(isWithinBoundaries(point))
return point;
else
return getValidPoint();


So after this, I end up with the valid point. My problem is that a valid point in Google Maps is not necessarily valid in StreetView. It might happen that this random point is somewhere in the globe not yet mapped in StreetView. I need it to be valid there as well.

I am aware that you can accomplish this using the JavaScript API v3 following this link:
https://developers.google.com/maps/documentation/javascript/reference#StreetViewService

You would do something like this:

var latLng = new google.maps.LatLng(12.121221, 78.121212);
streetViewService.getPanoramaByLocation(latLng, STREETVIEW_MAX_DISTANCE, function (streetViewPanoramaData, status) {
if (status === google.maps.StreetViewStatus.OK) {
//ok
} else {
//no ok
}
});


But I am hoping to do this using Android only. I am using the Google Play Services API by the way, and not the Google Maps v2 Android.

Can anyone shed some light?

EDIT:
Following ratana's suggestion, this is what I have so far:

svpView.getStreetViewPanoramaAsync(new OnStreetViewPanoramaReadyCallback() {
@Override
public void onStreetViewPanoramaReady(final StreetViewPanorama panorama) {
for(final LatLng point : points) {
System.out.println(point.latitude + " " + point.longitude);
panorama.setPosition(point, 1000);

final CountDownLatch latch = new CountDownLatch(1);

mHandlerMaps.post(new Runnable() {
@Override
public void run() {
if (panorama.getLocation() != null) {
System.out.println("not null " + panorama.getLocation().position);
writeToFile(panorama.getLocation().position.toString());
l.add(point);
}
latch.countDown();
}
});

try {
latch.await(4, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(l.toString());
}
});

Answer

EDIT: Google's official answer is here (https://code.google.com/p/gmaps-api-issues/issues/detail?id=7033), which points here: https://code.google.com/p/gmaps-api-issues/issues/detail?id=4823

The official solution involves using the official Google Street View Image API (free, no limit - https://developers.google.com/maps/documentation/streetview/metadata) via HTTPS.

OLD (DEPRECATED) ANSWER:

I've hacked together a workaround for this that is ugly but stays within the API, until Google updates it to allow querying for panoramas the way the iOS SDK does.

This involves creating a StreetViewPanoramaView, but not attaching it to the layout, and setting its position to the current location. And then testing if it has a panorama location following that.

This seems to work, but will be filing a request on the Android Google Maps API V2 (Which is part of the google play services API) tracker to add this, since the iOS SDK has this capability.

// Handle on the panorama view
private StreetViewPanoramaView svpView;

...

// create a StreetViewPanoramaView in your fragment onCreateView or activity onCreate method
// make sure to handle its lifecycle methods with the fragment or activity's as per the documentation - onResume, onPause, onDestroy, onSaveInstanceState, etc.
StreetViewPanoramaOptions options = new StreetViewPanoramaOptions();
svpView = new StreetViewPanoramaView(getActivity(), options);
svpView.onCreate(savedInstanceState);

...

// Snippet for when the map's location changes, query for street view panorama existence
private Handler mHandler = new Handler();
private static final int QUERY_DELAY_MS = 500;

// When the map's location changes, set the panorama position to the map location
svpView.getStreetViewPanorama().setPosition(mapLocationLatLng);

mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        if (svpView.getStreetViewPanorama().getLocation() != null) {
            // YOUR DESIRED ACTION HERE -- get the panoramaID, etc..
            // getLocation() -- a StreetViewPanoramaLocation -- will be null if there is no panorama
            // We have to delay this a bit because it may take some time before it loads
            // Note that adding an OnStreetViewPanoramaChangeListener doesn't seem to be reliably called after setPosition is called and there is a panorama -- possibly because it's not been added to the layout?
        }
    }
}, QUERY_DELAY_MS);

EDIT: to use the new Async API call:

svpView.getStreetViewPanoramaAsync(new OnStreetViewPanoramaReadyCallback() {
    @Override
    public void onStreetViewPanoramaReady(final StreetViewPanorama panorama) {
        panorama.setPosition(mapLocationLatLng, DEFAULT_SEARCH_RADIUS);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (panorama.getLocation() != null) {
                    // your actions here
                }
            }
        }, QUERY_DELAY_MS);
Comments