GPS를 이용하여 속도를 측정 해보기로 했습니다.

고등학교 물리 시간에 속시거(속도는 시간 / 거리)라고 외우도록 해서 아직도 기억을 하고 있는데

그외에도 물가중(물체의 힘은 가속도 x 중력)등 이제는 많이 잊어 버렸네요.

가장 중요한 건 단위를 알면 계산이 가능하다는 사실만 알고 있으라고 해서

대학교 물리, 고체, 유체, 열역학 시간에 도움이 많이 되었는데또 딴데로 가네.

 

사실 GPS로 속도 측정은 별로 쓸말이 없습니다.

GPS 측정 자체에 소도가 들어 있고 측정 시간도 들어 있어서 따로 열심히 계산할 것도 없고

차를 타고 다니며 확인을 하는게 전부입니다.

 


1. Location Class


많은 기능들이 있지만 이곳에서 사용하는 method를 기준으로 몇 개만 소개 합니다.


Type 

 Method

 설명

 float

 distanceTo(Location dest)

 주어진 위치와의 거리 차에 대한 근사치 값(m)

 long

 getTime()

 1970.1.1 기준 밀리세컨드

 float

 getSpeed()

 속도(m/s), 지상에서의 이동 기준


- distanceTo(Location dest)


ALocationBLocation이 있다고 할 때 두 위치의 거리 차를 구할 때 사용 합니다.

사용 방법은 : ALocation.distanceTo(Location BLocation)

 

- getTime()


주어진 위치 값을 구한 시간 정보를 가져 옵니다. ALocation 값을 구한 시간을 알고 싶다면

사용 방법 : ALocation.getTime();

 

- getSpeed()


위치의 변화가 있다면 직전 위치에서 현재 위치까지 이동하는데 소요된 시간으로 속도를

자동으로 계산해서 보여 줍니다.

ALocation에서의 속도를 구한다면

사용 방법 : ALocation.getSpeed()

 

 

2. 속도 측정 프로그램

 

2.1 신규 프로젝트 생성

 

프로젝트를 임의의 이름으로 생성해 줍니다.

 

여기서는 DeviceAndroid 4.0을 선택 하고



ActivityEmpty로 설정 했습니다.



 

2.2 Permission


위치에 대한 자료를 얻기 위해서는 장치 사용에 대한 권한 허가가 필요하고

GPS를 사용하기 위한 권한을 추가 합니다.

AndroidManifest.xml


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


2.3 Layout 작성

 

GridLayout을 이용해서 폼을 잡고 TextView를 두줄로 배열 했습니다.


<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:textSize="25dp"
        android:text="GPS Enable "
        />
    <TextView
        android:id="@+id/tvGpsEnable"
        android:text=":"
        android:textSize="25dp"
        />

… 이하 생략



2.4 MainActivity.java

 

- 권한 설정


AndroidManifest.xml에 추가한 권한 이외에도 Android 6.0 부터는 source 안에도 권한에 대한 체크를 하도록 하여 추가를 해줍니다.


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


- 위치정보 업데이트 등록


이동시 위치정보 업데이트를 위해 함수를 사용해 등록 합니다.


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


provider : 현재 위치정보 제공자가 GPS이고


minTime : 몇 초마다 정보를 update 할것인가 설정하는 최소 시간입니다.

현재 0을 주고 테스트 하는데 시간간격이 1000(1초)로 나오는 것으로 봐서 기본 1초 인듯합니다.

0으로 설정한 경우와 1000으로 한 경우 저속에서는 조금 차이가 있는 것 같습니다.

심심하면 시간과 거리 값을 조금씩 수정해서 테스트 해보세요.


minDistance : 거리 이동을 얼마나 할때마다 update 하는지에 대한 값입니다.


listener : 말 그대로 LocationListener 입니다.

 

- getSpeed()

double getSpeed = Double.parseDouble(String.format("%.3f", location.getSpeed()));

자동 속도 계산 값 입니다.  소수점 3자리로 하려고 하는데 2자리만 나오는 것으로 봐서

기본이 소수점 2자리 인 것 같습니다.

 

- 시간 간격

deltaTime = (location.getTime() - mLastlocation.getTime()) / 1000.0;

getTime()으로 얻은 시간은 milliseconds 이므로 1000 으로 나누어 주어야 m/s로 계산할 수 있습니다.

 

- 거리 간격

mLastlocation.distanceTo(location)

두 지점의 거리 차이를 구하며 meter 단위로 리턴 받습니다.

 

- 속도 계산

speed = mLastlocation.distanceTo(location) / deltaTime;

미터로 구한 거리를 시간 간격(밀리세턴드를 미터로 변경한 값)으로 나누어 구합니다.

 

- 위치 구하기 제거

ocationManager.removeUpdates(this);

프로그램이 중단 또는 종료되어 더 이상 위치를 구할 필요가 없는 경우 호출 합니다.


 

3. 결과



3.1 결과 화면

 

일정 속도로 이동하면 비슷한 결과가 나오는데 손으로 쥐고 걸어가면서 하면 두개의 값에 차이가 나는군요.


android gps 속도 측정



3.2 Source Code

 

GpsSpeed.7z



3.3 APK File


gpsSpeed.apk



4. Source Code

 


4.1 AndroidMainfest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.will.gpsspeed">

    <uses-permission android:name="android.permission.ACCESS_FINE_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>


4.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="GPS Speed 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:textSize="25dp"
            android:text="GPS Enable "
            />
        <TextView
            android:id="@+id/tvGpsEnable"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvGetSpeedLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Get Speed "
            />
        <TextView
            android:id="@+id/tvGetSpeed"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvCalSpeedLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Cal Speed "
            />
        <TextView
            android:id="@+id/tvCalSpeed"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvTimeLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Time "
            />
        <TextView
            android:id="@+id/tvTime"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvLastTimeLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="Last Time "
            />
        <TextView
            android:id="@+id/tvLastTime"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvTimeDifLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="시간 간격 "
            />
        <TextView
            android:id="@+id/tvTimeDif"
            android:text=":"
            android:textSize="25dp"
            />

        <TextView
            android:id="@+id/tvDistDifLabel"
            android:layout_gravity="right"
            android:textSize="25dp"
            android:text="거리 간격 "
            />
        <TextView
            android:id="@+id/tvDistDif"
            android:text=":"
            android:textSize="25dp"
            />
    </GridLayout>

</android.support.constraint.ConstraintLayout>


4.3 MainActivity.java


package com.example.will.gpsspeed;

import android.Manifest;
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 android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class MainActivity extends AppCompatActivity implements LocationListener {

    private LocationManager locationManager;
    private Location mLastlocation = null;
    private TextView tvGetSpeed, tvCalSpeed, tvTime, tvLastTime, tvGpsEnable, tvTimeDif, tvDistDif;
    private double speed;

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

        tvGetSpeed = (TextView)findViewById(R.id.tvGetSpeed);
        tvCalSpeed = (TextView)findViewById(R.id.tvCalSpeed);
        tvTime = (TextView)findViewById(R.id.tvTime);
        tvLastTime = (TextView)findViewById(R.id.tvLastTime);
        tvGpsEnable = (TextView)findViewById(R.id.tvGpsEnable);
        tvTimeDif = (TextView)findViewById(R.id.tvTimeDif);
        tvDistDif = (TextView)findViewById(R.id.tvDistDif);

        //권한 체크
        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) {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            String formatDate = sdf.format(new Date(lastKnownLocation.getTime()));
            tvTime.setText(": " + formatDate);  //Time
        }
        // GPS 사용 가능 여부 확인
        boolean isEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        tvGpsEnable.setText(": " + isEnable);  //GPS Enable
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000,0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        double deltaTime = 0;

        //  getSpeed() 함수를 이용하여 속도를 계산
        double getSpeed = Double.parseDouble(String.format("%.3f", location.getSpeed()));
        tvGetSpeed.setText(": " + getSpeed);  //Get Speed
        String formatDate = sdf.format(new Date(location.getTime()));
        tvTime.setText(": " + formatDate);  //Time

        // 위치 변경이 두번째로 변경된 경우 계산에 의해 속도 계산
        if(mLastlocation != null) {
            //시간 간격
            deltaTime = (location.getTime() - mLastlocation.getTime()) / 1000.0;
            tvTimeDif.setText(": " + deltaTime + " sec");  // Time Difference
            tvDistDif.setText(": " + mLastlocation.distanceTo(location) + " m");  // Time Difference
            // 속도 계산
            speed = mLastlocation.distanceTo(location) / deltaTime;

            String formatLastDate = sdf.format(new Date(mLastlocation.getTime()));
            tvLastTime.setText(": " + formatLastDate);  //Last Time

            double calSpeed = Double.parseDouble(String.format("%.3f", speed));
            tvCalSpeed.setText(": " + calSpeed);  //Cal Speed
        }
        // 현재위치를 지난 위치로 변경
        mLastlocation = location;
    }

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

    }

    @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, 1000,0, this);
    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @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, 1000,0, this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 위치정보 가져오기 제거
        locationManager.removeUpdates(this);
    }

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

    }
}

- copy coding -


예전에 초창기 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 -


tistory를 사용하면서 본문 내용 폰트가 너무 작아서 처음부터 변경을 하려고 생각만 하고 있다가

오랜만에 검색을 해보았지만 나오는 설명들이 나하고는 맞지가 않아 하는 수 없이

시간을 내서 직접 작업을 해보았습니다.

 

사용자 마다 스킨이 다를 텐데 저의 경우는 반응형 Square를 사용하고 있습니다.


tistory font


폰트는 다들 나눔 고딕을 많이 사용하는 것 같은데 검색을 하다 보니 본고딕(Noto Sans)

괜찮아 보여서 이것으로 선택을 하였습니다.


https://www.google.com/get/noto/#sans-kore


이곳에 가면 글씨의 원본을 볼 수 있습니다.


하단에는 캡쳐를 해왔는데 이미지가 작아서 별로인 것 같고 직접 가서 보시길 추천 합니다.

폰트는 다운로드를 받아서 설치를 하려고 했는데 생각보다 파일이 너무 크더군요.


요즘에 링크로도 해결이 되는데 굳이 다운받고 업로드 하기가 귀찮아 그냥 링크 방식으로 했습니다.




. 그럼 작업을 시작 합니다.

 

먼저 로그인을 하고 관리자 페이지 좌측 메뉴에서 [스킨 편집]을 선택 하면


우측에 [html 편집] 버튼이 보입니다.



[html 편집] 버튼을 누르면 화면이 바뀌면서 [HTML | CSS | 파일업로드] 가 나타 납니다.

 

여기서는 CSS를 선택 합니다.


아래 그림을 보고 저와 내용이 다르면 더 이상 이 글을 읽을 필요가 없습니다.


저와 css 구조가 달라서 적용이 안될 수 있습니다.



먼저 사용하지 않을 폰트는 주석처리를 하고 신규로 추가를 했습니다.


/*@import url(http://fonts.googleapis.com/css?family=Ubuntu+Condensed);*/

/*@import url(http://fonts.googleapis.com/earlyaccess/nanumgothic.css);*/

@import url(http://fonts.googleapis.com/earlyaccess/notosanskr.css);


그리고 font-size:를 키우고 font-family:에 폰트를 추가 해주고 사이트를 새로고침 했는데

영향이 없습니다.


textarea { font-size: 15px; font-family: 'Noto Sans KR', sans-serif; line-height: 200%; }


그래서 모든 font-family: 를 찾아서 수정하고 별 방법을 다 했는데 저하고는 하나도 맞지가 않더군요.


결국 divspan이 좌측 메뉴 구조와 내용에 영향을 주는 tag인걸 찾아내서

그냥 아래처럼 span, div를 추가하는 것으로 마무리를 했습니다.



이제는 글씨도 좀 커지고 제가 보기에는 만족 스럽습니다.


그럼 된거죠.


- copy coding -



eclipse에서 단순히 클릭만으로 angular 프로젝트를 생성해서 테스트를 진행 했었는데

이번에는 여기에 페이지를 추가하는 작업을 해보겠습니다.


단순 프로젝트는 [angular] eclipse에서 간단한 project 테스트 이곳을 참조 하세요.

 

페이지를 추가하는 방법도 매우 간단 합니다.



1. Component 추가


component 추가를 해보겠습니다.

 

프로젝트에 마우스를 놓고 우측 버튼을 클릭 합니다.

 

New > Component

 

를 선택 하면 컴포넌트 생성 팝업 창이 나타납니다.


angular component add


여기서 저는


company-vision


으로 Name을 설정하였습니다. 각자 편한 대로 기입하세요.


Component Name을 기입하면 하단에 Class 명칭도 실시간 자동으로 생성되는 모습을 볼 수 있습니다.


[Next] 버튼을 클릭 합니다.



그냥 [finish]를 선택 해도 되지만 한가지 보고 가려고 합니다.

 

바로 console mode 에서 어떤 명령으로 생성하는지 보여줍니다.



이제 [Finish] 버튼을 클릭 합니다.

 

company-vision 이라는 컴포넌트 명으로 디렉토리가 생성 되었고

새로운 웹페이지를 구성하는 4개의 파일도 생성 되었습니다.





2. 생성 파일


새로운 컴포넌트를 생성하면 기존 파일에는 어떤 변화가 있을까요?

1개의 파일에 변화가 발생 합니다.


app.module.ts 파일에 component를 자동으로 등록한걸 볼 수 있습니다.


import { CompanyVisionComponent } from './company-vision/company-vision.component';

 

/src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CompanyVisionComponent } from './company-vision/company-vision.component';

@NgModule({
  declarations: [
    AppComponent,
    CompanyVisionComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


그럼 신규 생성 파일들 중에 중요한 파일만 내용을 보겠습니다.


company-vision.component.ts 파일을 열어 보면 신규 생성 파일의 구성을 볼 수 있습니다.


htmlcss 파일 그리고 중요한 랜더링 입니다.


company-vision<app-company-vision> 랜더링 되겠네요.


/src/app/company-vision/company-vision.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-company-vision',
  templateUrl: './company-vision.component.html',
  styleUrls: ['./company-vision.component.css']
})
export class CompanyVisionComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}


그럼 html에는 어떤 내용이 있는지 보겠습니다.

 

/src/app/company-vision/company-vision.component.html


<p>
  company-vision works!
</p>


별거 없군요.




3. 신규 페이지 메인에 추가


 

지금 생성한 company-vision을 초기 웹페이지 index.html에 삽입이 가능 한지 해보겠습니다.

기존에

<body >
 <app-root > </app-root >
</body >


이렇게 되어 있는데 이곳에 새로 생성한 페이지를 추가 해서

<body>
  <app-root></app-root>

  <app-company-vision></app-company-vision>
</body>

이렇게 하고 테스트를 진행 해 보겠습니다.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MyNgProject</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>

  <app-company-vision></app-company-vision>
</body>
</html>


그리고

company-vision.component.html 도 글씨를 좀 키우겠습니다.

 

<h1>
<p>
  company-vision works!
</p>
</h1>

. 이제 프로젝트를 실행 합니다.


프로젝트 명에 마우스를 놓고 우측버튼을 클릭하고


Run As > Angular Web Application



잠시 기다리면 웹 브라우저가 열립니다.



? 없네요?


하단이 깨끗하군요.

멀 잘못 했을까요?


컴포넌트를 하나 생성 하면 company-vision에 웹 페이지관련 파일들이 들어 있고

기존 파일 중에 component들을 관리 하는 파일이 하나 있습니다.


/src/app/app.module.ts


바로 이 파일에 컴포넌트를 자동으로 추가를 해주지만 사용 여부는 개발자가 해줘야 겠죠.


bootstrap: [AppComponent, CompanyVisionComponent]


추가를 했습니다.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CompanyVisionComponent } from './company-vision/company-vision.component';

@NgModule({
  declarations: [
    AppComponent,
    CompanyVisionComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent, CompanyVisionComponent]
})
export class AppModule { }


다시 실행해 봅니다.



잘 나오는 군요.

 


4. 변수 추가


여기서 조금만 더 가보겠습니다.


/src/app/company-vision/company-vision.component.ts

 

이 파일의 class에 변수 하나를 추가하고


companyVision: string;

 

생성자에 변수의 초기값을 부여하겠습니다.


this.companyVision = 'Good Good!!';


import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-company-vision',
  templateUrl: './company-vision.component.html',
  styleUrls: ['./company-vision.component.css']
})
export class CompanyVisionComponent implements OnInit {

companyVision: string;

  constructor() {
    this.companyVision = 'Good Good!!';
  }

  ngOnInit() {
  }

}


/src/app/company-vision/company-vision.component.html


html에는 변수를 대입합니다.


<h1>
<p>
  company-vision: {{companyVision}}!
</p>
</h1>


자. 프로젝트를 다시 실행 합니다.



class에서 여러가지 java script(type script) 작업을 하면 html에 반영을 할 수 있습니다.

 

다음에는 좀더 가보도록 하겠습니다.


- copy coding -


1···107108109110111112113···118

+ Recent posts