Tracking Location

GPS sensor, permissions, Fused Location Provider Client

About

V OS Android existuje niekoľko spôsobov, ako je možné zistiť aktuálnu pozíciu zariadenia klienta. V rámci tohto cvičenia sa pozrieme na spôsob, v ktorom využijeme Fused Location Provider API. Toto API je súčasťou Google Play services, je jednoduché a hlavne šetrí batériu zariadenia.

Objectives

  • naučiť sa ošetriť Runtime Permissions
  • naučiť sa základy práce s Fused Provider API

Postup

New Project

V prvom kroku vytvoríme projekt našej aplikácie, nastavíme príslušné práva a doinštalujeme potrebné knižnice.

Úloha

Vytvorte si nový projekt s názvom Tracker a v ňom aktivitu s názvom MapsActivity, ktorú založíte práve na šablóne Maps Activity.

Úloha

Aktualizujte rozloženie aktivity pridaním tlačidla a elementu <TextView>.

Rozloženie môžete urobiť ručne alebo môžete využiť tento XML kód:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapsActivity">

    <LinearLayout
        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.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MapsActivity"
            android:layout_weight="1"
            />

        <TextView
            android:id="@+id/locationTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Latitude: no data available\\nLongitude: no data available"
            />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Get Location" />
    </LinearLayout>

</android.support.constraint.ConstraintLayout>

Úloha

Do manifestu projektu pridajte povolenia pre ACCESS_FINE_LOCATION a ACCESS_COARSE_LOCATION.

Úloha

Pridajte do projektu podporu pre Google Maps API a pre Constraint Layout.

Najprv overte, či máte podporu pre Google Play services nainštalovanú cez SDK Manager > SDK Tools > Google Play services. Ak nie, doinštalujte si ju.

Následne pridajte do gradle súboru modulu aplikácie závislosť pre play-services-maps a play-services-location pridaním nasledujúcich riadkov do časti dependencies. Okrem nich aj podporu pre constraint layout.

implementation 'com.google.android.gms:play-services-maps:16.0.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

Úloha

Otvorte si súbor google_maps_api.xml a podľa pokynov v ňom uvedených si vytvorte Google Maps API key.

Úloha

Pridajte do projektu podporu knižnice Butter Knife.

Do gradle súboru modulu aplikácie pridajte závislosť pre butterknife-compiler:

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

Úloha

Spustite vašu aplikáciu.

Ak ste postupovali podľa pokynov, mala by sa vám zobraziť aktivita s označeným mestom Sydney na mape, pod ktorým sa nachádza jeden pohľad pre text a jedno tlačidlo.

Tracker - Prvé spustenie

Úloha

Overte, či zariadenie má k dispozícii podporu GPS a ak nie, tak aplikáciu ukončite.

Ak budeme GPS hľadať pomocou objektu SensorManager, tak ho medzi dostupnými senzormi nenájdeme. Na to potrebujeme využiť iný prístup - napríklad sa opýtať Packagemanager-a, či zariadenie neobsahuje vlastnosť označenú ako FEATURE_LOCATION_GPS:

PackageManager packageManager = getPackageManager();
if(!packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)){
    Toast.makeText(this, "Device is missing GPS. Buy new one.", Toast.LENGTH_LONG).show();
    finish();
    return;
}

Retrieving Current Location

Aktuálnu polohu získame z objektu FusedLocationProviderClient. Na to však potrebujeme získať pre aplikáciu príslušné povolenia a vytvoriť objekt požiadavky, v ktorej nastavíme niekoľko vlastností. Aby bolo prezentovanie údajov zaujímavejšie, ako zdroj údajov pre GPS môžete použiť súbor morning.travel.gpx.

Úloha

Získajte objekt klienta FusedLocationProviderClient z objektu LocationServices.

Úloha

Vytvorte objekt typu LocationRequest, pomocou ktorého nastavíte vlastnosti požiadavky na GPS.

Keďže budeme chcieť pre našu aplikáciu zabezpečiť vysokú presnosť, nastavte:

  • prioritu požiadavky na hodnotu PRIORITY_HIGH_ACCURACY, a
  • interval aktualizácií na hodnotu 2 sekúnd.
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(2000);

Úloha

Nad vytvoreným klientom typu FusedLocationProviderClient zavolajte metódu requestLocationUpdates().

Po zavolaní tejto metódy začnú byť doručované správy o zmene polohy z GPS do anonymnej triedy typu LocationCallback, ktorá je parametrom metódy.

Ako Looper môžete uviesť null alebo použiť referenciu na hlavný Looper objekt aplikácie zavolaním metódy getMainLooper(), ktorý sa nachádza v hlavnom vlákne aplikácie.

V metóde onLocationResult() zaznamenajte aktuálne zistenú polohu do členskej premennej triedy MainActivity.

this.client.requestLocationUpdates(locationRequest, new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult result) {
        super.onLocationResult(result);
        Log.i(TAG, result.toString());
    }
}, null); // getMainLooper()

Úloha

Ošetrite dostupnosť prístupových práv pred volaním metódy requestLocationUpdates().

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                         Manifest.permission.ACCESS_COARSE_LOCATION},
            0);
    return;
}

this.client.requestLocationUpdates(locationRequest, new LocationCallback() {

    @Override
    public void onLocationResult(LocationResult result) {
        super.onLocationResult(result);
        Log.i(TAG, result.toString());
    }
}, null); // getMainLooper()

Úloha

Ošetrite kliknutie na tlačidlo Get Location tak, aby sa v pohľade pod ním zobrazila aktuálna poloha.

Úloha

Overte svoju implementáciu.

Ak ste postupovali správne, vaša aktivita po kliknutí na tlačidlo Get Location zobrazí aktuálne súradnice zistené z GPS.

Úloha

Zabezpečte, aby nedochádzalo k žiadnym aktualizáciám polohy v prípade, ak nie je aplikácia zapnutá, resp. viditeľná.

Podobne, ako v prípade akcelerátora a senzora magnetického poľa, sa na odber informácií o GPS prihlásime v metóde onResume() a odhlásime v metóde onPause(). Za týmto účelom si v metóde onCreate() vytvoríme členskú premennú pre objekt LocationCallback, ktorý vystupuje ako parameter pri volaní metód requestLocationUpdates() a removeLocationUpdates().

Úloha

Overte svoju implementáciu.

Google Maps Activity

V tomto kroku sa pozrieme na možnosti práce s Google Maps a budeme značkovať aktuálnu polohu na mape.

Úloha

Podobným spôsobom ako v predchádzajúcom kroku vytvorte a spojazdnite klienta FusedLocationProviderClient.

Úloha

Zabezpečte, aby sa na mape vykresľoval na aktuálnej polohe marker.

@Override
public void onLocationResult(LocationResult result) {
    super.onLocationResult(result);

    Log.i(TAG, result.toString());
    location = result.getLastLocation();

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

    mMap.addMarker(new MarkerOptions()
            .position(position)
            .title("here")
    );

    float zoomLevel = 16.0f; // mMap.getMaxZoomLevel();
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(position, zoomLevel));

}

Úloha

Overte svoju implementáciu.