Google Maps Android SMS Image Source unsplash.com.

Here is the GitHub – android-google-maps-SMS link for this project.

Introduction

In this tutorial, we will display and place a marker at the user’s current location in Google Maps for Android and send it via SMS. For doing this, we need to generate a Google Map API key. The process of generating Google Map API is in the tutorial here.

To display the user’s current location we need to implement some interfaces and their callbacks methods in Google Map.

OnMapReadyCallback(): This callback interface invokes when its instance is set on a MapFragment object. The onMapReady(GoogleMap) method of the OnMapReadyCallback interface is in use when the map is ready to use. In the onMapReady(GoogleMap) method we can add markers, listeners, and other attributes.

LocationCallback(): This interface is for receiving a notification when the device location has changed. The abstract method of LocationListener onLocationResult(LocationResult locationResult) is called when the location has changed.

What motivated me in doing this project? “How to pick the current location in Google Maps Android and send it via SMS”. I’m developing an android app that uses google maps and users are required to pick the current location and send it via SMS. This blog post will provide clear and precise instructions on how to implement: the current location in Google Maps and send SMS  in the same android app activity. Let’s see how to do this quickly.

How to Get Started

This guide is a quick start to adding a map to an Android app. Android Studio is the recommended development environment for building an app with the Maps SDK for Android and below are a few resources to get you prepared before starting this project:

Photo Preview

Glossary

Google Maps is a web mapping service developed by Google. It offers satellite imagery, aerial photography, street maps, 360° interactive panoramic views of streets, real-time traffic conditions, and route planning for traveling by foot, car, bicycle, and air, or public transportation.

SmsManager manages SMS operations such as sending data, text, and PDU SMS messages. Get this object by calling the static method getDefault(). To create an instance of SmsManager associated with a specific subscription ID, call getSmsManagerForSubscriptionId(int). This is typically used for devices that support multiple active subscriptions at once.

Steps:

Google Maps API in Android has revealed FusedLocationProviderClient under google API. FusedLocationProviderClient is for interacting with the location of an android device using the fused location provider. (NOTE: To use this feature, GPS must be turned on your device. To programmatically ask the user to turn on GPS, please check the previous article).

So let’s get started with the tutorial for getting the current location and sending SMS.

Step 1: 

Firstly, the FusedLocationProviderClient uses of the Google Play SDK. Therefore, open build.gradle and add the following dependencies as shown below:

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
//google maps
implementation 'com.google.android.gms:play-services-maps:16.0.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
}
view raw build.gradle hosted with ❤ by GitHub

Sync the project.

Step 2: 

Open activity_maps.xml and add the fragment for map and button for sending SMS as shown below:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" >
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
<Button
android:id="@+id/sendSms"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_sms"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:background="@android:color/holo_blue_dark"/>
</RelativeLayout>
view raw activity_maps.xml hosted with ❤ by GitHub

Step 3:

Open AndroidManifest.xml, and add the following permissions to your application to use location services.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.googlemapsms">
// Add these permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SEND_SMS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<activity
android:name="com.example.googlemapsms.MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.example.googlemapsms.MapsActivity">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
view raw AndroidManifest.xml hosted with ❤ by GitHub

This provides the ability to access location information at coarse and fine granularities. You can remove ACCESS_FINE_LOCATION this will still work with less precision. Note: The permissions model has changed starting in Marshmallow. If your targetSdkVersion >= 23 and you are running on a Marshmallow (or later) device, you may need to enable runtime permissions.

Step 4:

Since we are using dangerous permission of location, so we need to explicitly ask for permission. Also, before getting the current location of the user, override the checkLocationPermission() method and check if permissions are granted or not using the Alert Dialog and if the permission is granted and the GPS is enabled in the device. 

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
}
} else {
// if not allow a permission, the application will exit
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
System.exit(0);
}
}
}
}
view raw MapsActivity.java hosted with ❤ by GitHub

Step 5:

FusedLocationProviderClient takes care of all the connection logic on its own. Therefore we don’t need to initialize GoogleApiClient nor do we need to implement connection callbacks. We only need to initialize the FusedLocationProviderClient as shown below:

// Declare before onCreate()
FusedLocationProviderClient mFusedLocationClient;
// Initialize inside onCreate()
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
view raw MapsActivity.java hosted with ❤ by GitHub

Step 6:

Now, we need to define the type of location request that we want i.e. we can set the desired level of accuracy of location, the desired interval of location update, desired priority, etc. All these settings can be by using the LocationRequest data object. So, we can add the below code:

@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(120000); // two minute interval
mLocationRequest.setFastestInterval(120000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
} else {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
}
}
view raw MapsActivity.java hosted with ❤ by GitHub

Step 7:

If we want the last known location, we can implement and call the LocationCallback function that is responsible for getting the current location. The following is the code of LocationCallback:

LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() > 0) {
//The last location in the list is the newest
Location location = locationList.get(locationList.size() - 1);
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//move map camera
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(latLng.latitude, latLng.longitude)).zoom(16).build();
mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
};
view raw MapsActivity.java hosted with ❤ by GitHub

Step 8:

Finally, we will create a new function for sending the device’s location as a link via SMS.

public void sendingSms(){
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage("+254700000000", null, "https://www.google.com/maps/dir/?api=1&destination=lat,lng", null, null);
Toast.makeText(getApplicationContext(), "SMS SENT",
Toast.LENGTH_LONG).show();
}
view raw MapsActivity.java hosted with ❤ by GitHub

Do not forget to enter the phone number you want to receive the link in the destination address. It must begin with the country code.

Step 9:

After doing all the works and before running the application your full class code should look like the following:

package com.example.googlemapsms;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Looper;
import androidx.core.app.ActivityCompat;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import java.util.List;
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
GoogleMap mGoogleMap;
SupportMapFragment mapFrag;
LocationRequest mLocationRequest;
Location mLastLocation;
Marker mCurrLocationMarker;
FusedLocationProviderClient mFusedLocationClient;
Button sendSms;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
sendSms = findViewById(R.id.sendSms);
getSupportActionBar().setTitle("Google Map Sms");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
// ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.SEND_SMS},1);
sendSms.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendingSms();
}
});
}
public void sendingSms(){
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage("+254700000000", null, "https://www.google.com/maps/dir/?api=1&destination=lat,lng", null, null);
Toast.makeText(getApplicationContext(), "SMS SENT",
Toast.LENGTH_LONG).show();
}
@Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(120000); // two minute interval
mLocationRequest.setFastestInterval(120000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
} else {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
}
}
LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() > 0) {
//The last location in the list is the newest
Location location = locationList.get(locationList.size() - 1);
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//move map camera
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(latLng.latitude, latLng.longitude)).zoom(16).build();
mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
};
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
mGoogleMap.setMyLocationEnabled(true);
}
} else {
// if not allow a permission, the application will exit
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
System.exit(0);
}
}
}
}
}
view raw MapsActivity.java hosted with ❤ by GitHub

So now run your application and ensure your GPS settings are on. You should see your current location on the google map. If you press the SEND_SMS button, the contact you entered in the previous step will receive a link to your location.

Future Directions

After that, display details of the place (a business or other point of interest) at that location using the Maps SDK for Android, the Places SDK for Android, and the fused location provider in the Google Play services location APIs.

Learning Strategies and Tools

In conclusion, we have learned about how the Google Maps API includes an all-new way to load maps. Activities now have to implement the OnMapReady CallBack interface, which comes with onMapReady() method override that is executed every time we run SupportMapFragment.getMapAsync(OnMapReadyCallback); and the call is successfully completed. This activity code will provide basic functionality for including a Google Map using a SupportMapFragment.

Checking the specific API documentation to determine whether the connection is in use. Therefore, LocationRequest objects are for requesting quality of service for location updates. In conclusion, FusedLocationProviderClient has very strong services.

Reflective Analysis

One of the unique features of mobile applications is location awareness. Mobile users take their devices with them everywhere. Therefore, adding location awareness to your app offers users a more contextual experience. The location APIs available in Google Play services facilitate adding location awareness to your app. For instance with automated location tracking, Geo-fencing, and activity recognition.

In this blog, we learn how to display the changed location of the user in your app. Send SMS using the smsManager() function. We have used the Fused Location API for the same purpose. You can use this concept while making some ride-sharing application.

In conclusion, it took me a total of 20 hours to finish the project and the blog.  Finally, everything is available in this GitHub repository.

Link to the previous post: https://blog.learningdollars.com/2020/07/26/how-to-show-enable-location-dialog-without-navigating-to-settings-page-like-google-maps-in-android/.

That’s all for this tutorial!