반응형

Activity Recognition Transition API ?

처음에 이 API 에 대한 소개를 봤을 때만 해도, Activity 가 흔히 안드로이드의 4대 컴포넌트 중 하나인 액티비티인 줄 알고 해석을 했었는데 알고보니 위 Activity 는 정말 단어 그대로 사용자의 "활동" 입니다. 그러니 헷갈리지 않게 잘 분별하도록 합시다.

 

옛날에는 스마트폰 사용자가 현재 걷고 있는 중인지, 달리는 중인지, 차를 탔는지 등에 대해 알기 위해서 따로 제공해주는 API 가 없어 개발자가 일일히 위치 센서와 자이로 센서 등을 활용하여 나름의 계산식을 세워 구해야만 했습니다.

 

하지만 지금은 안드로이드에서 Activity Recognition Transition API 를 제공해주고 있기 때문에, 특별한 이유가 따로 있지 않은 이상 손쉽게 유저의 활동 상태를 알 수 있게 됐습니다.

 

 

환경 설정

먼저 Activity Recognition Transition API 를 사용하기 위해서는 2가지 작업이 준비되어야 합니다. 하나는 Google 의 play-services-location 라이브러리에 대해 의존성을 갖는 것이고, 나머지 하나는 AndroidManifest.xml 파일에 권한을 선언해줘야 합니다.

 

1. build.gradle (app 수준)

implementation 'com.google.android.gms:play-services-location:17.1.0'

2. AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.myapp">
  
  <!-- API 버전 28 이하 -->
  <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
  <!-- API 버전 29 이상 -->
  <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

  ...
</manifest>

보시다시피 Android API 29 버전을 기준으로 선언해줘야 하는 권한이 다르기 때문에 반드시 둘 다 선언해줍니다.

 

그리고 API 버전 29 이상에서 선언해준 ACTIVITY_RECOGNITION 권한은 Runtime Permission 이기 때문에 액티비티 구현부에 런타임 권한을 요청하는 코드를 추가해줘야 합니다.

 

 

ActivityTransitionRequest 생성

ActivityTransitionRequest 객체는 유저의 활동이 변경 됐을 때 통지되는 객체입니다. 이를 생성하기 위해서는 ActivityTransition 객체를 담고 있는 리스트 객체를 선언하고, 수신하고자 하는 활동에 대해 추가해줘야 합니다.

 

ActivityTransition 객체는 Builder 객체를 통해 생성하며, DetectedActivity 클래스에 정의된 상수(IN_VEHICLE, ON_BICYCLE, ON_FOOT, STILL, WALKING, RUNNING 등)를 통해 type 을 설정하고 ActivityTransition 클래스에 정의된 상수(ACTIVITY_TRANSITION_ENTER, ACTIVITY_TRANSITION_EXIT 등) 을 설정해줍니다.

ActivityTransition 에 대해 보다 자세한 내용은 여기를 참고하세요.

 

예시는 아래와 같습니다.

val transitions: List<ActivityTransition> = 
        listOf(
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.WALKING)	// 걷기
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                .build(),
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.WALKING)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                .build(),
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.STILL)	// 움직임 없음
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                .build(),
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.STILL)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                .build()
        )

 

이제 ActivityTransitionRequest 객체를 생성할 수 있습니다..

val request = ActivityTransitionRequest(transitions)

 

PendingIntent 활용하기

ActivityTransitionRequest 객체를 생성했다면 이제 PendingIntent 를 생성해줍니다. PendingIntent 를 생성하기 위한 다양한 방법이 있지만 이번 예제에서는 BroadcastReceiver 를 등록한 상황을 가정해보겠습니다.

val intent = Intent(TRANSITIONS_RECEIVER_ACTION)  // 자신만의 action 값을 정의합니다
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)

 

이제 request 와 pendingIntent 가 준비 되었으니 등록해보도록 하겠습니다.

ActivityRecognition.getClient(this)
    .requestActivityTransitionUpdates(request, pendingIntent)
    .addOnSuccessListener {
        Log.d(LOG_TAG, "Transitions API was successfully registered")
    }.addOnFailureListener { e ->
        Log.d(LOG_TAG, "Transitions Api could not be registered : $e")
    }

 

등록하는 시점에 대해 주의할 점은 API 29 버전 이상에 대해서는 런타임 권한 요청이 승인된 경우에 등록하도록 신경써줘야 합니다.

 

등록하는 것과 반대로 해지하는 것도 비슷합니다. 주로 onStop() 콜백에서 해지해주면 됩니다.

ActivityRecognition.getClient(this)
    .removeActivityTransitionUpdates(pendingIntent)
    .addOnSuccessListener {
        Log.d(LOG_TAG, "Transitions successfully unregistered.")
    }
    .addOnFailureListener { e ->
        Log.d(LOG_TAG, "Transitions could not be unregistered : $e")
    }

 

이제 BroadcastReceiver 와 ActivityRecognition 을 등록했다면, BroadcastReceiver 의 onReceive() 에 다음과 같이 작성하여 Transition 이벤트를 처리할 수 있습니다.

 

override fun onReceive(context: Context?, intent: Intent?) {
    // 앞서 intent 에 설정해둔 action 과 일치하는지 검사
    if (intent?.action != TRANSITIONS_RECEIVER_ACTION) {
        return
    }

    if (ActivityTransitionResult.hasResult(intent)) {
        val result: ActivityTransitionResult = ActivityTransitionResult.extractResult(intent) ?: return

        for (event in result.transitionEvents) {
            val message = "Transition : ${if(event.activityType == DetectedActivity.WALKING) "WALKING" else "STILL"} (${event.transitionType})"
            Log.d(LOG_TAG, message)
        }
    }
}

 

이 동작은 에뮬레이터로 확인하기에는 어려움이 있기 때문에 실제 디바이스에서 테스트 할 것을 권장합니다.

 

위 코드에 대한 예제는 Github 에서 확인할 수 있습니다.

반응형
반응형