예전에 초창기 GPS 관련 자료를 얻기 위해 세미나를 찾아 다니고 자료를 수집할 때

우리나라에는 위성이 없으니 얻어 써야 하고 GPS 정보 자체가 군용으로 사용되고 있어서

일부러 오차를 약 20m 정도 나도록 신호를 주고 있다고 했었습니다.

그래서 그 20m를 보정하는 것 자체가 큰 기술이라고 했는데 이제는 핸드폰에서 아무때나

꺼내서 사용할 수 있게 되었으니 참 신기한 일입니다.

물론 그동안 수많은 지도 업체와 네비 업체가 문을 닫았지요.



1. 좌표값 생성


위치정보를 구하는 방법은 2가지가 있습니다.


1.1 GPS Provider


3각 측량의 방법으로 좌표를 위성을 이용하여 취득합니다.

그러므로 위성의 전파를 잡지 못하는 실내에서는 사용이 어렵고 실외에서는 건물 또는

계곡이 깊으면 전파를 잡기 어려워 위치를 잡지 못할 수 있습니다.


1.2 Network Provider


이동통신 기지국 또는 WiFi  access point들을 이용하여 측정을 있습니다.


1.3 Passive Provider


위치를 구하는 방법이 2가지라고 했는데 Passive 방식은 좌표를 직접 구하는 것이 아니고

다른 어플리케이션이나 서비스가 좌표 값을 구하면 단순히 값을 받아 오기만 하는

전달자 역할을 하기 때문에 값을 얻을 수는 있지만 구한다고는 없습니다.



2. LocationManager 개요



2.1 Permission


모바일 기기의 장치를 사용하려면 사용 허가가 필요합니다.

provider 별 사용 허가에 대한 변수들 입니다.

대부분 ACCESS_FINE_LOCATION 이거 하나면 권한을 받을 수 있습니다.


 Provider

 permission

 GPS

 android.permission.ACCESS_FINE_LOCATION

 Network

 android.permission.ACCESS_COARSE_LOCATION 또는

 android.permission.ACCESS_FINE_LOCATION

 Passive

 android.permission.ACCESS_FINE_LOCATION



2.2 Provider


Type 

 Parameter

 설명

 String

 GPS_PROVIDER

 GPS를 이용 위치 제공

 String

 NETWORK_PROVIDER

 기지국, WiFi를 이용 위치 제공

 String

 TYPE_STEP_COUNTER

 기존 좌표값 이용 위치 제공



2.3 Method


Type

 Method / 설명

 List

 getAllProviders()

  - 모든 Provider 정보를 리턴 한다.

 LocationProvider

 getProvider(String name)

  - 명칭(name)에 대한 Provider 정보를 리턴 한다.

 List

 getProviders(boolean enabledOnly)

  - true를 입력하면 현재 사용 가능한 Provider의 목록을 리턴 합니다.

  - false를 입력하면 비활성화 포함 모든 Provider의 목록을 리턴 합니다.

 boolean

 isProviderEnabled(String provider)

  - 입력한 Provider의 명칭에 대한 사용 가능 여부를 리턴 합니다.

 void

 removeUpdates(LocationListener listener)

  - 더 이상 위치 정보가 필요 없을 때 위치 정보 수집을 종료 시킵니다.

 void

 requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)

  - Provider를 등록하고 기입한 거리와 시간의 변동이 있을 때 마다 update 된 위치 정보를 리턴 합니다.



3. Location 프로그램



그럼 좌표 값을 얻기가 얼마나 쉬운지 한번 알아보도록 하겠습니다.



3.1 신규 프로젝트 생성


프로젝트 명을 적당하게 명명해서 생성 하고 기타 설정 사항도 본인의 기호에 맞게 설정 하여 신규 프로젝트를 하나 생성 합니다.

저는 항상 DeviceAndroid 4.0을 선택 하고



Activity Empty로 설정 합니다.




3.2 Permission


장치 사용에 대한 권한 허가는 두개 다 적어 줍니다.


AndroidManifest.xml

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


3.3 Layout 작성

 

지금까지 Layout은 그냥 TextView를 죽 나열하는 방식으로 작업 했는데

이번에는 기입 하는게 많고 우측 정렬도 필요해서 GridLayout을 사용했습니다.


<GridLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="2"
    app:layout_constraintTop_toBottomOf="@+id/tvTitle"
    >

참고로 여기서는 그냥 android:columnCount=”2” 이것만 보시면 됩니다.

컬럼이 2개 이니까 아래에 나열된 TextView들은 자동으로 2개씩 나누어져서 하나의 Row를 만듭니다.

HTMLTable tag보다 참 편하죠.

 

3.4 MainActivity.java


- 권한 설정


이미 Manifest에 권한을 추가 했지만 Android 6.0 부터는 source 안에도 권한에 대한 체크를 해야 한다는군요.

저는 location를 사용하는 모든 곳에 추가를 했습니다.

안그러면 실행은 되는데 빨간 줄이 자꾸 나와서 눈에 거슬리더군요


if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    //권한이 없을 경우 최초 권한 요청 또는 사용자에 의한 재요청 확인
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION) &&
            ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)) {
        // 권한 재요청
        ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
        return;
    } else {
        ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
        return;
    }
}

- 초기 좌표값


프로그램이 시작되면 우선 초기 좌표 값을 기록하도록 했습니다.


Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocation != null) {
    double lng = lastKnownLocation.getLongitude();
    double lat = lastKnownLocation.getLatitude();
    Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat);
    tvGpsLatitude.setText(":: " + Double.toString(lat ));
    tvGpsLongitude.setText((":: " + Double.toString(lng)));
}

그리고 초기 값을 나타낼 때만 중간에 콜론을 두개 찍었는데( :: ) 이러면 초기값이 그대로 인지

아니면 변경된 값을 얻어오는지 확인을 할 수 있습니다.

 

- Provider 작동 확인


기기에 어떤 Provider들이 있는지 값을 가져오고


listProviders = locationManager.getAllProviders();

Provider별 작동 여부를 확인 하여 Update가 되도록 합니다.

requestLocationUpdates()의 두번 째 값은 갱신 시간이고 세번 째 값은 갱신 이동 거리입니다.

저는 둘다 0으로 해서 계속 값을 갱신 하도록 했습니다.

이렇게요.


if(listProviders.get(i).equals(LocationManager.GPS_PROVIDER)) {
    isEnable[0] = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    tvGpsEnable.setText(": " +  String.valueOf(isEnable[0]));

    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}

- LocationChange


onLocationChanged(Location location)에서 이동을 하면 좌표 값이 변경되고 변경된 좌표를 얻어옵니다.


if(location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
    latitude = location.getLatitude();
    longitude = location.getLongitude();
    tvGpsLatitude.setText(": " + Double.toString(latitude ));
    tvGpsLongitude.setText((": " + Double.toString(longitude)));
    Log.d(TAG + " GPS : ", Double.toString(latitude )+ '/' + Double.toString(longitude));
}

- 수집 중단


어플리케이션을 사용하지 않을 때는 더 이상 좌표 수집을 하지 않도록 중단해야 합니다.

안그러면 계속 백그라운드에서 작업을 하여 리소스를 잡아먹겠죠.


locationManager.removeUpdates(this);



4. 결과



4.1 결과 화면


GPS는 잘 잡히는데 Network은 안잡히는 걸로 나오네요.


gps network provider android


구해진 좌표 값은 google map과 연동하면 바로 위치를 확인 할 수 있습니다.

실제로 google map과 연동 테스트를 하려면 구글에 회원 가입을 하고

맵을 사용하겠다고 해서 API 키값을 받아야 합니다.

귀찮으니 그냥 간단하게 구글 맵에서 위치를 확인 할 수 있는데요.

구글 지도를 웹으로 열면 주소창의 URL에 좌표가 같이 나타 납니다.

그럼 거기에 핸드폰으로 구한 좌표를 콤마로 구분해서 변경해 주면 위치를 확인할 수 있습니다.

 

https://www.google.com/maps/@37.5555062,126.7976293,14z




4.2 Source Code


LocProvider.7z



4.3 APK File


LocProvider.apk




5. Full Source Code


원래 취지대로 그냥 복사해서 붙여넣기를 해서 사용할 때를 위해 전체 소스를 남김니다



5.1 AndroidManifest.xml


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

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

    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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


5.2 activity_main.xml


<?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=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android Location Test"
        android:layout_marginTop="20dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <GridLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:columnCount="2"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        >

        <TextView
            android:id="@+id/tvGpsEnableLabel"
            android:layout_gravity="right"
            android:text="GPS Enable "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvGpsEnable"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvNetworkEnableLabel"
            android:layout_gravity="right"
            android:text="Network Enable "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvNetworkEnable"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvPassiveEnableLabel"
            android:layout_gravity="right"
            android:text="Passive Enable "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvPassiveEnable"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvGpsLocationLabel"
            android:layout_gravity="right"
            android:text="GPS Location "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvGpsLocation"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvGpsLatitudeLabel"
            android:layout_gravity="right"
            android:text="GPS Latitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvGpsLatitude"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvGpsLongitudeLabel"
            android:layout_gravity="right"
            android:text="GPS Longitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvGpsLongitude"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvNetworkLocationLabel"
            android:layout_gravity="right"
            android:text="Network Location "
            android:textSize="20dp"
        />
        <TextView
            android:id="@+id/tvNetworkLocation"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvNetworkLatitudeLabel"
            android:layout_gravity="right"
            android:text="Network Latitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvNetworkLatitude"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvNetworkLongitudeLabel"
            android:layout_gravity="right"
            android:text="Network Longitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvNetworkLongitude"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvPassiveLocationLabel"
            android:layout_gravity="right"
            android:text="Passive Location "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvPassiveLocation"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvPassiveLatitudeLabel"
            android:layout_gravity="right"
            android:text="Passive Latitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvPassiveLatitude"
            android:text=""
            android:textSize="20dp"
            />

        <TextView
            android:id="@+id/tvPassivekLongitudeLabel"
            android:layout_gravity="right"
            android:text="Passive Longitude "
            android:textSize="20dp"
            />
        <TextView
            android:id="@+id/tvPassivekLongitude"
            android:text=""
            android:textSize="20dp"
            />
    </GridLayout>
</android.support.constraint.ConstraintLayout>


5.3 MainAcitvity.java


package com.example.desk.locprovider;

import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity implements LocationListener {

    private LocationManager locationManager;
    private List<String> listProviders;
    private TextView tvGpsEnable, tvNetworkEnable, tvPassiveEnable, tvGpsLatitude, tvGpsLongitude;
    private TextView tvNetworkLatitude, tvNetworkLongitude, tvPassiveLatitude, tvPassivekLongitude;
    private String TAG = "LocationProvider";

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

        tvGpsEnable = (TextView)findViewById(R.id.tvGpsEnable);
        tvNetworkEnable = (TextView)findViewById(R.id.tvNetworkEnable);
        tvPassiveEnable = (TextView)findViewById(R.id.tvPassiveEnable);
        tvGpsLatitude = (TextView)findViewById(R.id.tvGpsLatitude);
        tvGpsLongitude = (TextView)findViewById(R.id.tvGpsLongitude);
        tvNetworkLatitude = (TextView)findViewById(R.id.tvNetworkLatitude);
        tvNetworkLongitude = (TextView)findViewById(R.id.tvNetworkLongitude);
        tvPassiveLatitude = (TextView)findViewById(R.id.tvPassiveLatitude);
        tvPassivekLongitude = (TextView)findViewById(R.id.tvPassivekLongitude);

        //권한 체크
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

        Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (lastKnownLocation != null) {
            double lng = lastKnownLocation.getLongitude();
            double lat = lastKnownLocation.getLatitude();
            Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat);
            tvGpsLatitude.setText(":: " + Double.toString(lat ));
            tvGpsLongitude.setText((":: " + Double.toString(lng)));
        }
        lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        if (lastKnownLocation != null) {
            double lng = lastKnownLocation.getLongitude();
            double lat = lastKnownLocation.getLatitude();
            Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat);
            tvNetworkLatitude.setText(":: " + Double.toString(lat ));
            tvNetworkLongitude.setText((":: " + Double.toString(lng)));
        }

        lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
        if (lastKnownLocation != null) {
            double lng = lastKnownLocation.getLongitude();
            double lat = lastKnownLocation.getLatitude();
            Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat);
            tvPassiveLatitude.setText(":: " + Double.toString(lat ));
            tvPassivekLongitude.setText((":: " + Double.toString(lng)));
        }

        listProviders = locationManager.getAllProviders();
        boolean [] isEnable = new boolean[3];
        for(int i=0; i<listProviders.size();i++) {
            if(listProviders.get(i).equals(LocationManager.GPS_PROVIDER)) {
                isEnable[0] = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                tvGpsEnable.setText(": " +  String.valueOf(isEnable[0]));

                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
            } else if(listProviders.get(i).equals(LocationManager.NETWORK_PROVIDER)) {
                isEnable[1] = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                tvNetworkEnable.setText(": " +  String.valueOf(isEnable[1]));

                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
            } else if(listProviders.get(i).equals(LocationManager.PASSIVE_PROVIDER)) {
                isEnable[2] = locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
                tvPassiveEnable.setText(": " +  String.valueOf(isEnable[2]));

                locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
            }

        }

        Log.d(TAG, listProviders.get(0) + '/' + String.valueOf(isEnable[0]));
        Log.d(TAG, listProviders.get(1) + '/' + String.valueOf(isEnable[1]));
        Log.d(TAG, listProviders.get(2) + '/' + String.valueOf(isEnable[2]));
    }

    @Override
    public void onProviderEnabled(String provider) {
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
        locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
    }


    @Override
    public void onLocationChanged(Location location) {

        double latitude = 0.0;
        double longitude = 0.0;

        if(location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            tvGpsLatitude.setText(": " + Double.toString(latitude ));
            tvGpsLongitude.setText((": " + Double.toString(longitude)));
            Log.d(TAG + " GPS : ", Double.toString(latitude )+ '/' + Double.toString(longitude));
        }

        if(location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            tvNetworkLatitude.setText(": " + Double.toString(latitude ));
            tvNetworkLongitude.setText((": " + Double.toString(longitude)));
            Log.d(TAG + " NETWORK : ", Double.toString(latitude )+ '/' + Double.toString(longitude));
        }

        if(location.getProvider().equals(LocationManager.PASSIVE_PROVIDER)) {
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            tvPassiveLatitude.setText(": " + Double.toString(latitude ));
            tvPassivekLongitude.setText((": " + Double.toString(longitude)));
            Log.d(TAG + " PASSIVE : ", Double.toString(latitude )+ '/' + Double.toString(longitude));
        }

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @Override
    protected void onStart() {
        super.onStart();
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //권한이 없을 경우 최초 권한 요청 또는 사용자에 의한 재요청 확인
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION) &&
                    ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)) {
                // 권한 재요청
                ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
                return;
            } else {
                ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
                return;
            }
        }

    }

    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
        locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
    }
}

- copy coding -


+ Recent posts