Monday, December 21, 2015

Android Google Maps V2 Tutorial




Step: 1
======

1) Generate a Google Maps API Key using this URL.

1.1) To generate a debug SHA1 key for testing apps for development use below command in windows command prompt.
keytool -list -v -keystore "C:\Users\pratap.kesaboyina\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

1.2) To generate a release SHA1 key for production usage( when releasing your app to google play store, debug key will not work. You need a release SHA1 Key)

keytool -list -v -keystore "C:\AndroidFiles\AppKeyStore.jks" -alias "Your App Alias Name"



1.3) Go ahead and add Maps Api Key in the manifest file and also add Permissions in the manifest File.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pratap.mapssample">


<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />


<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="com.pratap.mapssample.MapsSampleActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_debug_key" />
</application>

</manifest>


3) Add dependencies to your app in build.gradle file


dependencies {
compile 'com.google.android.gms:play-services-maps:8.1.0'
compile 'com.google.android.gms:play-services-location:8.1.0'

}


Step: 2
======
Create an xml layout file with MapFragment



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />


</LinearLayout>


Step: 3
======
Now create an Activity class



package com.pratap.mapssample;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import java.text.DateFormat;
import java.util.Date;

/**
* Created by pratap.kesaboyina on 18-12-2015.
*/
public class MapsSampleActivity extends AppCompatActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener, ResultCallback<LocationSettingsResult> {

// UI Views
private Toolbar toolbar;
private TextView tvTitle;
private MapFragment mMapFragment;

private GoogleMap googleMap;


// Map Settings

private final int[] MAP_TYPES = {GoogleMap.MAP_TYPE_SATELLITE,
GoogleMap.MAP_TYPE_NORMAL,
GoogleMap.MAP_TYPE_HYBRID,
GoogleMap.MAP_TYPE_TERRAIN,
GoogleMap.MAP_TYPE_NONE};
private int MAP_TYPE_INDEX = 1;

protected static final String TAG = "MapsSampleActivity";

/**
* Constant used in the location settings dialog.
*/
protected static final int REQUEST_CHECK_SETTINGS = 0x1;

/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;

/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;

// Keys for storing activity state in the Bundle.
protected final static String KEY_REQUESTING_LOCATION_UPDATES = "requesting-location-updates";
protected final static String KEY_LOCATION = "location";
protected final static String KEY_LAST_UPDATED_TIME_STRING = "last-updated-time-string";

/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;

/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
protected LocationRequest mLocationRequest;

/**
* Stores the types of location services the client is interested in using. Used for checking
* settings to determine if the device has optimal location settings.
*/
protected LocationSettingsRequest mLocationSettingsRequest;

/**
* Represents a geographical location.
*/
protected Location mCurrentLocation;


/**
* Tracks the status of the location updates request. Value changes when the user presses the
* Start Updates and Stop Updates buttons.
*/
protected Boolean mRequestingLocationUpdates;

/**
* Time when the location was updated represented as a String.
*/
protected String mLastUpdateTime;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mMapFragment = (MapFragment) getFragmentManager()
.findFragmentById(R.id.map);
mMapFragment.getMapAsync(this);
mRequestingLocationUpdates = false;


// Update values using data stored in the Bundle.
updateValuesFromBundle(savedInstanceState);

// Kick off the process of building the GoogleApiClient, LocationRequest, and
// LocationSettingsRequest objects.
buildGoogleApiClient();
createLocationRequest();
buildLocationSettingsRequest();
checkLocationSettings();
}


/**
* Updates fields based on data stored in the bundle.
*
* @param savedInstanceState The activity state saved in the Bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Update the value of mRequestingLocationUpdates from the Bundle, and make sure that
// the Start Updates and Stop Updates buttons are correctly enabled or disabled.
if (savedInstanceState.keySet().contains(KEY_REQUESTING_LOCATION_UPDATES)) {
mRequestingLocationUpdates = savedInstanceState.getBoolean(
KEY_REQUESTING_LOCATION_UPDATES);
}

// Update the value of mCurrentLocation from the Bundle and update the UI to show the
// correct latitude and longitude.
if (savedInstanceState.keySet().contains(KEY_LOCATION)) {
// Since KEY_LOCATION was found in the Bundle, we can be sure that mCurrentLocation
// is not null.
mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION);
}

// Update the value of mLastUpdateTime from the Bundle and update the UI.
if (savedInstanceState.keySet().contains(KEY_LAST_UPDATED_TIME_STRING)) {
mLastUpdateTime = savedInstanceState.getString(KEY_LAST_UPDATED_TIME_STRING);
}

}
}

/**
* Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}

/**
* Sets up the location request. Android has two location request settings:
* {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control
* the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
* the AndroidManifest.xml.
* <p/>
* When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
* interval (5 seconds), the Fused Location Provider API returns location updates that are
* accurate to within a few feet.
* <p/>
* These settings are appropriate for mapping applications that show real-time location
* updates.
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

/**
* Uses a {@link com.google.android.gms.location.LocationSettingsRequest.Builder} to build
* a {@link com.google.android.gms.location.LocationSettingsRequest} that is used for checking
* if a device has the needed location settings.
*/
protected void buildLocationSettingsRequest() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true); // To hide never button on the Popup dialog.
mLocationSettingsRequest = builder.build();

}

/**
* Check if the device's location settings are adequate for the app's needs using the
* {@link com.google.android.gms.location.SettingsApi#checkLocationSettings(GoogleApiClient,
* LocationSettingsRequest)} method, with the results provided through a {@code PendingResult}.
*/
protected void checkLocationSettings() {
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient,
mLocationSettingsRequest
);
result.setResultCallback(this);


}

@Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");

mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mCurrentLocation != null) {
/*mLatitudeText.setText(String.valueOf(mCurrentLocation.getLatitude()));
mLongitudeText.setText(String.valueOf(mCurrentLocation.getLongitude()));*/
setCurrentLocation(mCurrentLocation);

}
}


/**
* Callback that fires when the location changes.
*/
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
// updateLocationUI();

setCurrentLocation(mCurrentLocation);

Toast.makeText(this, getResources().getString(R.string.location_updated_message),
Toast.LENGTH_SHORT).show();
}


@Override
public void onMapReady(GoogleMap gMap) {
googleMap = gMap;


}


@Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "Connection suspended");
}

@Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}


/**
* The callback invoked when
* {@link com.google.android.gms.location.SettingsApi#checkLocationSettings(GoogleApiClient,
* LocationSettingsRequest)} is called. Examines the
* {@link com.google.android.gms.location.LocationSettingsResult} object and determines if
* location settings are adequate. If they are not, begins the process of presenting a location
* settings dialog to the user.
*/
@Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
startLocationUpdates();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to" +
"upgrade location settings ");

try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MapsSampleActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " +
"not created.");
break;
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
Log.i(TAG, "User agreed to make required location settings changes.");
startLocationUpdates();
break;
case Activity.RESULT_CANCELED:
Log.i(TAG, "User chose not to make required location settings changes.");
break;
}
break;
}
}


private void setCurrentLocation(Location location) {


LatLng mapCenter = new LatLng(location.getLatitude(), location.getLongitude());


googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mapCenter, 16));
// googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), null);

googleMap.setMapType(MAP_TYPES[MAP_TYPE_INDEX]);
//googleMap.setTrafficEnabled(true);
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setZoomControlsEnabled(true);

// Flat markers will rotate when the map is rotated,
// and change perspective when the map is tilted.
//BitmapDescriptorFactory.fromResource(R.drawable.direction_arrow
/*googleMap.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
.position(mapCenter)
.flat(true)
.rotation(90));*/
googleMap.clear();

googleMap.addMarker(new MarkerOptions()
.title("My Location ")
.position(mapCenter)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
);


CameraPosition cameraPosition = CameraPosition.builder()
.target(new LatLng(location.getLatitude(), location.getLongitude()))
.zoom(16f)
.bearing(0.0f)
.tilt(0.0f)
.build();

// Animate the change in camera view over 2 seconds
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition),
2000, null);

}

@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}

@Override
public void onResume() {
super.onResume();
// Within {@code onPause()}, we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
}
}

@Override
protected void onPause() {
super.onPause();
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
}
}

@Override
protected void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
}


/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
mLocationRequest,
this
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
mRequestingLocationUpdates = true;
//setButtonsEnabledState();
}
});

}


/**
* Removes location updates from the FusedLocationApi.
*/
protected void stopLocationUpdates() {
// It is a good practice to remove location requests when the activity is in a paused or
// stopped state. Doing so helps battery performance and is especially
// recommended in applications that request frequent location updates.
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient,
this
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
mRequestingLocationUpdates = false;
// setButtonsEnabledState();
}
});
}


/**
* Stores activity data in the Bundle.
*/
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(KEY_REQUESTING_LOCATION_UPDATES, mRequestingLocationUpdates);
savedInstanceState.putParcelable(KEY_LOCATION, mCurrentLocation);
savedInstanceState.putString(KEY_LAST_UPDATED_TIME_STRING, mLastUpdateTime);
super.onSaveInstanceState(savedInstanceState);
}
}



ScreenShots
======



Demo:










References
https://developers.google.com/maps/documentation/android-api/code-samples



No comments:

Post a Comment