Arvutiteaduse instituut
  1. Kursused
  2. 2022/23 sügis
  3. Mobiilirakenduste arendus (LTAT.06.021)
EN
Logi sisse

Mobiilirakenduste arendus 2022/23 sügis

  • Main
  • Lectures
  • Labs
  • Homeworks & Assignments
  • Task submission
  • Extra Materials
  • Best Practices
  • Results
  • Quizes
  • Projects
    • Presentations & Report
    • Teams & Topics
    • Grading & Submission

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 Accelerometer 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 either:
      • make MainActivity implement the interface
      • create a new class for it
      • or create an anonymous object inside MainActivity which implements it.


    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 with the interfaces 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 (e.g. by logging the values) 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 TextView according to the device position.
    • 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.
    • You also need to set "exported" to true for MapsActivity, to allow the system to launch it

To use Google Map in your application you need an Google API key. Use THIS KEY (get password from lab instructor / check Slack #lab7) or or refer to https://developers.google.com/maps/gmp-get-started to create your own API key

  • In AndroidManifest.xml - insert your API key inside the android:name="com.google.android.geo.API_KEY" metadata XML tag

Run the project. You can see the default pin is added to Sydney.

If you are not seeing a map, and instead see a grey screen

  • Double-check that you didn't include whitespace by mistake when copying the API key
  • Check the version of the maps library in build.gradle, you may need to update it to a newer version (e.g. 'com.google.android.gms:play-services-maps:18.1.0' )
  • Let us modify the onMapReady()function of MapsActivity
    • Change the coordinates and title of the Sydney Marker so that it shows Delta building instead
    • Coordinates of Delta: 58.385254, 26.725064
    • Change the "moveCamera" line, update the Zoom level of the camera as well with:
    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

For the next parts, our app needs the android.permission.ACCESS_COARSE_LOCATION and android.permission.ACCESS_FINE_LOCATION permissions

  • Add them both to the Manifest file

In this lab, we will manually grant the permissions 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

Open the folder containing the adb binary (adb.exe on Windows) in command-line. Issue this command (change the package, permission package accordingly!) to grant both permissions to the app:

  adb shell pm grant com.example.myapppackage android.permission.SOME_PERMISSION_HERE

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
    • (Add this code to your newly created file)
    • This code uses FusedLocationProviderClient to get location updates
    • NB! This code also relies on the dependency (add to build.gradle):
    implementation 'com.google.android.gms:play-services-location:21.0.0' // Location Requests
  • In the MapsActivity class, write declare a class field for the LocationHelper, instantiate it in onCreate().
  • Now use functions of the LocationHelper (requestLoactionUpdates, stopLocationUpdates) to register for location update results.
    • requestLoactionUpdates( callback: LocationCallback) need you to implement the LocationCallback (which is an abstract class).
      • You can create an anonymous object which extends that class, and override the onLocationResult( result: LocationResult) method of the LocationCallback interface
       val myCallBackImplementation = object: LocationCallback(){
                  override fun onLocationResult(result: LocationResult) {
                        // .. do something with result
                      }
                  }
      
    • Inside onLocationResult, update the Google Map by adding a 2nd marker (located at the acquired user location), and moving the camera to it
 inside onMapReady() to obtain the current location and then pin it on the map:
      mMap.addMarker(MarkerOptions().position(coords).title("You are here "))
      mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(coords,15F))

Note: right now, we are adding a *new marker* on every location update. Eventually, this will clutter the map and waste device memory. A better solution would be declare a single marker as a class field, and update its location on every update!

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
  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused