b2cloud

30th May 2014

StreetView in Android

Tutorial By 3 years ago

As part of the 4.4 Play Store Services release Google has extended the Maps API to include Native StreetView. I’m super excited about this, in fact I would go so far as to say that if your app has a map it needs StreetView! I know that’s a big claim and the reason I make this claim is that while a map is great at showing a user where a landmark is and how to get from one point to another, it does a very bad job of showing you what to expect when you get there. This, of course, is where StreetView excels!  Providing users access to StreetView as part of your maps solution not only gives your users the ability to see what the landmark looks like before they get there, but also what landmarks surround it, what type of road it’s on, whether or not it has curb side parking available, etc, etc. The best part about it is that StreetView can be embedded inside your app with very little effort.

So let us begin! In this tutorial we’ll  be using the SupportStreetViewPanoramaFragment to create a self contained fragment that takes a set of longitude and latitude coordinates, positions you at the street near your coordinates, and points you in the direction of your coordinates.

Setup

As with all my tutorials I’m going to assume you’re using Android Studio, or at least using the Gradle build system. The first step is to setup Google Play Services Maps, now I could take you through each step but Google already has done this better than I could have. You can find Googles setup page here

You’re back, great, now open up the Android SDK manager and ensure you have the latest version of Play Service and ensure you have added the latest version as a dependency and we’re ready to begin!

dependencies {
    compile 'com.google.android.gms:play-services:4.0.4.52'
}

Implementation

The first thing we’ll do is create a new SupportFragment called StreetViewFragment that extends the SupportStreetViewPanoramaFragment, this will allow us to keep all custom StreetView logic inside our fragment class. While we’re at it we’ll create a newInstance method that take a set of latitude and longitude coordinates and returns a new instance of the StreetViewFragment

public class StreetViewFragment extends SupportStreetViewPanoramaFragment{
    public static final StreetViewFragment newInstance(double latitude, double longitude){
        Bundle args = new Bundle();
        args.putDouble("latitude, latitude);
        args.putDouble("longitude", longitude);

        StreetViewFragment fragment =  new StreetViewFragment();
        fragment.setArguments(args);
        return fragment;
    }
}

The newInstance methods is fairly simple, it stores the geo coordinates in the fragment arguments for use later, and returns a new StreetViewFragment instance.

The next step is to override the onCreateView so we can start to setup and position the StreetView camera

public class StreetViewFragment extends SupportStreetViewPanoramaFragment{
    ...
    
    @Override
    onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance){
        View fragmentView = super.onCreateView(inflater, container, savedInstance);
        
        StreetViewPanorama panorama = getStreetViewPanorama();
        //Check we got a valid instance of the StreetViewPanorama
        if(panorama != null){
            double latitude = args.getDouble("latitude", -1);
            double longitude = args.getDouble("longitude", -1);
            panorama.setPosition(new LatLng(latitude, longitude));
        }
    }
}

Just a quick note on positioning the StreetView panorama, while this might be obvious the position of your panorama will not be the location you pass in but the closes road side position. What’s not obvious is that the panorama will not point towards your target location, but instead will point to 0 degrees or North. So while the code thus far will position the panorama correctly it will more than likely be pointing the wrong way. In order to fix that we’ll first create a helper method that will tell us the angle between two locations.

public class StreetViewFragment extends SupportStreetViewPanoramaFragment{
    ...
    
    private float getBearing(double startLat, double startLng, double endLat, double endLng){
        Location startLocation = new Location("startlocation");
        startLocation.setLatitude(startLat);
        startLocation.setLongitude(startLng);
        
        Location endLocation = new Location("endlocation");
        endLocation.setLatitude(endLat);
        endLocation.setLongitude(endLng);

        return startLocation.bearingTo(endLocation);
    }
}

Before we can use this method we need to get the camera location, and the camera location is not set until after the onCreateView method as been called. Luckily for us we can get the camera location by listening to the onStreetViewPanoramaChange event onCreateView. Just remember to remove the listener unless you want StreetView to point towards your coordinates every time the user moves the camera.

public class StreetViewFragment extends SupportStreetViewPanoramaFragment implements 
    StreetViewPanorama.OnStreetViewPanoramaChangeListener{
    ...
    
    @Override
    onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance){
        View fragmentView = super.onCreateView(inflater, container, savedInstance);
        
        StreetViewPanorama panorama = getStreetViewPanorama();
        //Check we got a valid instance of the StreetViewPanorama
        if(panorama != null){
            double latitude = args.getDouble("latitude", -1);
            double longitude = args.getDouble("longitude", -1);
            panorama.setPosition(new LatLng(latitude, longitude));
            panorama.setOnStreetViewPanoramaChangeListener(this);
        }
    }

    @Override
    public void onStreetViewPanoramaChange(StreetViewPanoramaLocation streetViewPanoramaLocation){
        //Get the angle between the target location and road side location
        float bearing = getBearing(
            streetViewPanoramaLocation.position.latitude,
            streetViewPanoramaLocation.position.longitude,
            getArguments().getDouble("latitude", -1),
            getArguments().getDouble("longitude", -1));
        
        //Remove the listener 
        getStreetViewPanorama().setOnStreetViewPanoramaChangeListener(null);
       //Change the camera angle
        StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder()
            .bearing(bearing)
            .build();
        getStreetViewPanorama().animateTo(camera, 1);
    }
}

  • rajendra pawar

    what values should be passed with this private float getBearing(double startLat, double startLng, double endLat, double endLng) in order to use it in program
    ?

  • Alius Petraška

    line “@Override onCreateView” throws an error: return type required

Recommended Posts

Write JNI wrappers for Android

Post by 3 years ago

Following are the steps that you need to follow in order to make things working – 1. Setting up the NDK on my machine 2. Learn how to write JNI wrappers 3. Learn C++ briefly so

Got an idea?

We help entrepreneurs, organizations and established brands from around
the country bring ideas to life. We would love to hear from you!