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 -



1. 진동 함수

 

진동 테스트는 무척 단순합니다.

 

진동을 일으키는 방법은 3가지가 있습니다.

 

첫째는 정해진 시간 만큼 한번 작동시키기

 

둘쨰는 정해진 패턴으로 한번 작동 시키기

 

마지막 세번째는 정해진 패턴으로 반복 작동 시키기


입니다.

 

모두 vibrate( ) 함수를 사용하는데 어떤 parameter 를 넘겨 주느냐에 따라

작동법이 달라 집니다.

 

첫번째 한번 작동은 param으로 milliseconds를 넘겨 줍니다.

   vibrate(1000);  // 10001초 입니다.

 

두번째와 세번째는 정해진 패턴의 longmilliseconds의 배열을 넘겨 줍니다.


배열의 형태는

long[] vloop = {0, 500, 100, 500, 100,….}; //5000.5초 입니다.

이고


배열 값의 의미는 {무진동 시간, 진동 시간, 무진동 시간, 진동 시간, ……}

배열 이므로 원하는 만큼 원하는 숫자를 기입하면 됩니다.


그리고 두번째 param에 따라 반복 여부가 결정 됩니다.


-1 이면 1회 진동, 0이상이면 반복 진동입니다.

vibrate(패턴, -1);   //1회 패턴 진동

vibrate(패턴, 0이상); //패턴 반복 진동


그런데 여기서 반복 진동도 2가지 종류로 나누어 집니다.

물론 핸드폰마다 조금씩 다른데, 정상적으로(동일 패턴) 무한 반복하는 것도 있습니다.


함수 사용

 진동 방식

 진동 형태

 vibrate(패턴, -1);

 패턴 1회 진동

 패턴 시간씩 진동/ 종료

 vibrate(패턴, 0);

 패턴 반복 진동

 패턴 시간씩 진동/ 패턴 시간씩 진동

 vibrate(패턴, 1);

 패턴 반복 진동

 패턴 시간씩 진동/ 짧은 시간씩 진동

 vibrate(패턴, 2);

 패턴 반복 진동

 패턴 시간씩 진동/ 패턴 시간씩 진동

 vibrate(패턴, 3);

 패턴 반복 진동

 패턴 시간씩 진동/ 짧은 시간씩 진동

 vibrate(패턴, 4);

 패턴 반복 진동

 패턴 시간씩 진동/ 패턴 시간씩 진동

 ...

  ...

  ...


이런 진동 형태가 반복이 되는데


0, 2, 4, … 짝수의 값은 패턴에 기입한 시간의 패턴이 무한 반복이 되지만


1, 3, 5,… 홀수 값일 경우에는 최초에만 정해진 시간 패턴으로 진동을 하고

그 다음 부터는 매우 짧게 틱, , 틱 하는 정도로만 진동을 합니다.

 


2. 진동 테스트 프로그램

 

2.1 진동 사용 허가


핸드폰의 진동자를 사용하기 위해서는 사용허가를 해야 합니다.


AndroidManifest.xmlpermission을 추가 합니다.


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

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

    <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>


2.2 Layout 작성

 

기능이 단순해서 vibrate( ) 함수의 parameter 별로 버튼을 만들었습니다.


[1], [패턴 1], [패턴 반복], [종료]


<?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">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:text="1초"
        app:layout_constraintBottom_toTopOf="@+id/button2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.621" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="48dp"
        android:text="패턴"
        app:layout_constraintBottom_toTopOf="@+id/button3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="48dp"
        android:text="반복"
        app:layout_constraintBottom_toTopOf="@+id/button4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="96dp"
        android:text="종료"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</android.support.constraint.ConstraintLayout>


 

2.3 Main Source

 

Vibrator를 선언하고 버튼을 눌러 진동을 테스트 합니다.

 

추가로 바탕을 터치해도 진동이 되도록 했습니다.


@Override

    public boolean onTouchEvent(MotionEvent event) { }


단순해서 머 더 설명할게 없습니다.


package com.example.desk.vibrator;

import android.content.Context;
import android.os.Vibrator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

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

        Button btn1 = (Button)findViewById(R.id.button);
        Button btn2 = (Button)findViewById(R.id.button2);
        Button btn3 = (Button)findViewById(R.id.button3);
        Button btn4 = (Button)findViewById(R.id.button4);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn3.setOnClickListener(this);
        btn4.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        long[] vloop = {0, 500, 100, 500, 100, 500, 100};
        if(v.getId() == R.id.button) {
            vibrator.vibrate(1000);  //1초 작동
        } else if(v.getId() == R.id.button2) {
            vibrator.vibrate(vloop, -1); //패턴 1회 작동
        } else if(v.getId() == R.id.button3) {
            vibrator.vibrate(vloop, 0); //패턴 반복
        } else if(v.getId() == R.id.button4) {
            vibrator.cancel();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        final Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        switch(action) {
            case MotionEvent.ACTION_DOWN :    //화면을 터치했을때 이벤트
                vibrator.vibrate(new long[] {0,100}, 0);  //계속 진동
                break;
            case MotionEvent.ACTION_UP :      //화면을 터치했다 땠을때 이벤트
                vibrator.cancel();  //진동 취소
                break;
            case MotionEvent.ACTION_MOVE :    //화면을 터치하고 이동할때 이벤트
                vibrator.vibrate(new long[] {0,100}, 0);  //계속 진동
                break;
        }
        return super.onTouchEvent(event);
    }
}



3. 결과

 


3.1 결과 화면


버튼과 바탕화면을 클릭 또는 이동 하면서 테스트 하세요.


android vibrator sensor


3.2 Source Code

 

 

Vibrator.7z



3.3 APK File


Vibrator.apk


- copy coding -



중력 센서(TYPE_GRAVITY)는 중력 가속도에 대한 값을 반환하는 센서 입니다.

중력 센서를 가속도 센서 비교 (TYPE_ACCELEROMETER / TYPE_LINEAR_ACCELERATION)를 할 때

다루지 않은 이유는 가속센서는 조금만 움직여도 가속도 값이 더해져서 표시가 됩니다.


중력 센서는 그냥 중력만 표시할 뿐 그 이외의 어떠한 값이 포함 되지 않습니다.

, 아무리 핸드폰을 흔들고 달려보아도 총 중력 값이 변하지 않고 항상 9.8의 값을 유지 합니다.

이 말은 z축의 값이 9.8이 되도록 한다면 핸드폰은 완전한 평형을 이루고 있다는 뜻이고

중력 센서를 이용하면 간단하게라도 수평계를 만들 수 있습니다.

 


1 중력 센서



1.1 중력 센서 이벤트 값


TYPE_GRAVITY 센서가 작동 되면 리턴되는 값으로 다음과 같은 value를 넘겨 주며 단위는 가속도(m/s2) 입니다.


Sensor 

 Sensor event data

 표현 값

 측정 단위

 TYPE_GRAVITY

 SensorEvent.values[0]

 x축 중력 강도

 m/s²

 TYPE_GRAVITY

 SensorEvent.values[1]

 y축 중력 강도

 m/s²

 TYPE_GRAVITY

 SensorEvent.values[2]

 z축 중력 강도

 m/s²


 

2 중력 센서 프로젝트

 


2.1 신규 프로젝트 생성


안드로이드 스튜디오에서 적당한 이름으로 프로젝트를 하나 생성합니다.

 

2.2 Layout 작성


activity_main.xml

 

중력 센서가 보내오는 x, y, z축의 m/s2 값들을 출력할 수 있는 TextView를 작성합니다.

 


<?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="Gravity Sensor"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvXaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="X axis : 0"
        />
    <TextView
        android:id="@+id/tvYaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvXaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Y axis : 0"
        />
    <TextView
        android:id="@+id/tvZaxis"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvYaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Z axis : 0"
        />
    <TextView
        android:id="@+id/tvGravity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvZaxis"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Total Gravity : 0"
        />
</android.support.constraint.ConstraintLayout>


2.3 Java Source


MainActivity.java

소스를 보면 알겠지만 기존 센서와 동일한 프로세스로 작동이 됩니다.

핸드폰이 움직일 때 마다 각 축으로부터 받는 중력을 합한 중력 총량을 구합니다.



package com.example.desk.sensorgravity;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor gravitySensor;
    private double total;
    TextView tvXaxis, tvYaxis, tvZaxis, tvGravity;

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

        tvXaxis = (TextView)findViewById(R.id.tvXaxis);
        tvYaxis = (TextView)findViewById(R.id.tvYaxis);
        tvZaxis = (TextView)findViewById(R.id.tvZaxis);



        tvGravity = (TextView)findViewById(R.id.tvGravity);

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, gravitySensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor == gravitySensor) {

            total = Math.sqrt(Math.pow(event.values[0],2) + Math.pow(event.values[1], 2) + Math.pow(event.values[2] , 2));

            tvXaxis.setText("X axis : " + String.format("%.2f", event.values[0]));
            tvYaxis.setText("Y axis : " + String.format("%.2f", event.values[1]));
            tvZaxis.setText("Z axis : " + String.format("%.2f", event.values[2]));
            tvGravity.setText("Total Gravity : "  + String.format("%.2f", total) + " m/s\u00B2");
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
}


3. 결과

 

3.1 결과 화면

 

핸드폰을 평평한 곳에 놓았을 때나 흔들고 이동을 하여도 전체 중력 값은 동일한 것을

확인 할 수 있습니다.


android gravity sensor



3.2 Source Code


 

SensorGravity.7z



 

3.3 APK File


SensorGravity.apk


- copy coding -


1···11121314151617

+ Recent posts