Lab 7 - Android Sensors and Location Based Services
In this lab session, we will:
- Read data from the accelerometer
- Use Google maps API and GPS to locate the phone
1. Orientation indicator that displays the device orientation as Left, Middle and Right
- Open this base project
- The Main Activity has 3 TextViews in a row, with texts “Left, Middle, Right”. The plan is to dynamically set the background color based on the sensor value (as shown in the above figure).
In MainActivity.kt:
- Create an instance of SensorManager to access the sensor service (see code below)
- Create an instance of Sensor class, access the Accelerometer sensor through the SensorManager, and then register to the sensor listener.
- To register to sensor events, you have to implement the SensorEventListener interface and implement its two methods:
- onAccuracyChanged ( .. )
- onSensorChanged( .. )
- You can make MainActivity implement the interface, create a new class for it or create an anonymous object inside MainActivity which implements it.
- To register to sensor events, you have to implement the SensorEventListener interface and implement its two methods:
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(<<sensorListener>>, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
- Now read the Accelerometer data of with the function onSensorChanged(event: SensorEvent)
override fun onSensorChanged(event: SensorEvent) { val x = event.values[0] val y = event.values[1] val z = event.values[2] . . . . . . }
- Observe which of the axis values changes in which situation and how large the values are. Tracking one axis is enough to get the result as shown in the above screenshot.
- Add code which sets the background color of the right TextView accordingly.
- Tip: Kotlin when statement is handy here
Note: Similar to using BroadcastReceiver, we should be be attentive with when we are registering the listener and also appropriately unregister them, to avoid draining resources unnecessarily.
2. Google Maps
2.0 Add the Google Maps SDK to your project
- Let's add a Google Maps Activity to our project
In Android Studio, select New -> Activity -> Gallery...
and choose the Maps Activity. This will set up most things for us.
- To make the app open MapsActivity instead of MainActivity by default, move the Intent filters in Manifest from MainActivity to MapsActivity.
To use Google Map in your application you need an Google API key. Use THIS KEY (get password from lab instructor) or or refer to https://developers.google.com/maps/gmp-get-started to create your own API key
- Insert your API key inside the google_maps_api.xml (res->values)
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">YOUR_KEY_HERE</string>
Run the project. You can see the default pin is added to Sydney. So, let us modify the onMapReady()function, which pins to Delta Center, move camera there and zoom to 12.
val delta = LatLng(58.385254, 26.725064) mMap.addMarker(MarkerOptions().position(delta).title("Delta Centre")) mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(delta,12F))
2.1 Reading the current location from the GPS and show it on the map
For this, we can use the Android Location API that can be used to track your mobile device’s current location.
Permission Handling
This lab, we will manually grant the permission via command-line, using Android Debug Bridge (ADB). Open up a terminal/commandline, and depending on your OS, locate the adb binary. It is bundled with the Android SDK installation, inside the platform-tools folder, so the exact location may depend upon where you installed Android Studio / Android SDK (how to find your SDK location)
- Windows : For default Android Studio installation:
\AppData\Local\Android\Sdk\platform-tools
- Windows : For default Android Studio installation:
Open the folder containing the adb binary (adb.exe on Windows) in command-line. Issue this command (change the package accordingly!) to grant permissions to the app:
adb shell pm grant com.example.myapppackage android.permission.ACCESS_FINE_LOCATION
If you have issues with adb, troubleshoot if adb can see your device with the command adb devices
Adding the code
- Create a new Kotlin class file called LocationHelper.kt, which uses FusedLocationProviderClient to get location updates (add this code to your project)
- NB! This code also relies on the dependency (add to build.gradle):
implementation 'com.google.android.gms:play-services-location:18.0.0' // Location Requests
- In the MapsActivity class, write a function to create an instance of the LocationHelper class
- Now call functions of the LocationHelper inside onMapReady() to obtain the current location and then pin it on the map:
override fun onMapReady(googleMap: GoogleMap) { . . . . . . . . mMap.addMarker(MarkerOptions().position(currentLocation).title("You are here ")) mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLocation,15F)) }
2.2 My Location Button
Alternatively, we can use the "My Location" Button, which also displays the current location.
- Add the following line to onMapReady() function ( you can comment out the previous GPS location code)
mMap.setMyLocationEnabled(true)
Once you click on the button, it will show your current location. Let’s make this app more interactive. Once you touch on the current location it will pin the location with the address. For this, we need our MapsActivity class implements OnMyLocationClickListener interface.
class MapsActivity : AppCompatActivity(), OnMapReadyCallback ,GoogleMap.OnMyLocationClickListener { . . . . }
To get the address of the current location, we use google Reverse Geocoding API. https://developers.google.com/maps/documentation/geocoding/intro#ReverseGeocoding
- Add the following codes to the override fun onMyLocationClick(location: Location) function
override fun onMyLocationClick(location: Location) { val latitude = location.latitude val longitude = location.longitude var latlng= LatLng(latitude,longitude) val geocoder = Geocoder(this) val addresses = geocoder.getFromLocation(latitude, longitude, 1) val loc = addresses[0].getAddressLine(0) mMap.addMarker(MarkerOptions().position(latlng).title("You are here $loc")) mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng,15F)) }
- After that add mMap.setOnMyLocationClickListener(this) to the onMapReady() function
3. Draw a line on the map
Here we just draw a straight line between two locations without considering the real routes between them. We draw the line from the Delta building to the current location of the device. However, google maps API provides a facility to draw a route on the map with waypoints.
- Create a function which use Polyline
fun drawPolyLine(){ var start = LatLng(58.385254, 26.725064 ) var end=LatLng(latitude,longitude) mMap.addPolyline(PolylineOptions().add(start,end)) }
- Now call this function in the onMyLocationClick() to draw the line