한 걸음 두 걸음

안드로이드 시스템 프로그래밍 #04 ] 근접 정보 활용하기 본문

FrontEnd/mobile system programming

안드로이드 시스템 프로그래밍 #04 ] 근접 정보 활용하기

언제나 변함없이 2019. 3. 20. 09:33
반응형

근접 경보 등록 함수

LocationManager에서 제공하는 기능중 하나가
LocationManager에 정의된 메소드(void addProximityAlert(double latitude, double longitude, float radius,long expiration, PendingIntent intent))를 이용하여 원하는 영역을 등록해 놓으면 위치 감시하는 작업은 내부적으로 처리하여 결과를 통보해주는 것입니다.
앱에서는 인텐트를 수신하여 처리하기만 하면 되고, 위치 데이터를 사용하는 것이기 때문에 아래의 퍼미션을 허락해주어야 합니다.
Android.permission.ACCESS_FINE_LOCATION

관심 있는 곳의 좌표(latitude, longitude)에 반경(radius)를 설정해두고, 이 범위 안에 들어오면 근접 경보가 울립니다. expiration 만기 시간을 설정할 수 있어 일정 시간이 지나면 알림을 취소시킬 수 있습니다. ( -1 값을 넣으면 시간 제한 없이 계속 있습니다.)
PendingIntent를 사용하여 영역에 들어가거나 영역에서 나갈 때(KEY_PROXIMITY_ENTERING이라는 key를 갖는 boolean 값을 전달. 이 값이 true이면 영역에 들어간 것이고 false이면 영역을 나간 것) 실행할 인텐트를 생성하거나 브로드캐스트를 보낼 수도 있습니다.

근접 경보 해제 함수

void removeProximityAlert(PendingIntent intent)
: 액티비티가 활성화되어 있을 때만 감시를 하는 경우는 onResume 메소드에서 근접 경보를 등록하고, onPause에서 해제하는 방식으로 사용합니다.

과제제출코드

MainActivity.java

package kr.ac.koreatech.swkang.msp04_proximityalert;

import android.Manifest;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements LocationListener {
    LocationManager locManager;
    AlertReceiver receiver;
    TextView locationText;
    PendingIntent proximityIntent;
    boolean isPermitted = false;
    boolean isLocRequested = false;
    boolean isAlertRegistered = false;
    final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;

    double lat = 0;
    double lng = 0;

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

        locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locationText = (TextView) findViewById(R.id.location);

        requestRuntimePermission();
    }

    private void requestRuntimePermission() {
        //*******************************************************************
        // Runtime permission check
        //*******************************************************************
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {

                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

            } else {

                // No explanation needed, we can request the permission.

                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
            }
        } else {
            // ACCESS_FINE_LOCATION 권한이 있는 것
            isPermitted = true;
        }
        //*********************************************************************
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // read_external_storage-related task you need to do.

                    // ACCESS_FINE_LOCATION 권한을 얻음
                    isPermitted = true;

                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.

                    // 권한을 얻지 못 하였으므로 location 요청 작업을 수행할 수 없다
                    // 적절히 대처한다
                    isPermitted = false;

                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request
        }
    }

    public void onClick(View view) {
        if (view.getId() == R.id.getLocation) {
            try {
                if(isPermitted) {
                    locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0, this);
                isLocRequested = true;
            }
                else
                    Toast.makeText(this, "Permission이 없습니다..", Toast.LENGTH_LONG).show();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
        } else if (view.getId() == R.id.alert) {
            // 근접 경보를 받을 브로드캐스트 리시버 객체 생성 및 등록
            // 액션이 kr.ac.koreatech.msp.locationAlert인 브로드캐스트 메시지를 받도록 설정
            receiver = new AlertReceiver();
            IntentFilter filter = new IntentFilter("kr.ac.koreatech.msp.locationAlert");
            registerReceiver(receiver, filter);

            // ProximityAlert 등록을 위한 PendingIntent 객체 얻기
            Intent intent = new Intent("kr.ac.koreatech.msp.locationAlert");
            proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
            try {
                // 근접 경보 등록 메소드
                // void addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)
                // 아래 위도, 경도 값의 위치는 2공학관 420호 창가 부근
                locManager.addProximityAlert(lat, lng, 20, -1, proximityIntent);
            } catch (SecurityException e) {
                e.printStackTrace();
            }
            isAlertRegistered = true;
        }else if(view.getId() == R.id.alert_release){
            // 자원 사용 해제
            try {
                if(isAlertRegistered) {
                    locManager.removeProximityAlert(proximityIntent);
                    unregisterReceiver(receiver);
                }
                Toast.makeText(getApplicationContext(),"근접 경보 해제 되었습니다.",Toast.LENGTH_SHORT).show();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onPause(){
        super.onPause();

        // 자원 사용 해제
        try {
            if(isLocRequested) {
                locManager.removeUpdates(this);
                isLocRequested = false;
            }
            if(isAlertRegistered) {
                locManager.removeProximityAlert(proximityIntent);
                unregisterReceiver(receiver);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        lat = location.getLatitude();
        lng = location.getLongitude();

        locationText.setText("위도 : " + location.getLatitude()
                + " 경도 : " + location.getLongitude());
    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

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

    }
}

AlertReceiver

package kr.ac.koreatech.swkang.msp04_proximityalert;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.widget.Toast;

public class AlertReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        boolean isEntering = intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
        // boolean getBooleanExtra(String name, boolean defaultValue)

        if(isEntering)
            Toast.makeText(context, "목표 지점에 접근중입니다..", Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context, "목표 지점에서 벗어납니다..", Toast.LENGTH_LONG).show();
    }
}
반응형