Activity Recognition in Android - GeeksforGeeks

15 Oct, 2021
In this article, we are going to learn about an API called the Activity Recognition Transition API or Transition API  which is intended for detecting the activity of a particular user such as driving, walking or running, etc. There are many applications that use this Activity Recognition Transition API. For example, a kilometer finder app starts running when you start driving a car or a bike and stops when you stop driving. Other examples of this Activity Recognition can be any Health and Fitness app that determines how many meters or kilometers you are running or walking on a particular day and after that, you can find the calories burnt on that day and much more.
Here we are going to make an application that will detect the user’s activity like still, running, walking, driving, or something else. A sample screenshot image is given below to get an idea about what we are going to do in this article. 
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add dependencies
// Google Play Service’s Location
implementation ‘com.google.android.gms:play-services-location:18.0.0’
implementation “androidx.preference:preference-ktx:1.1.1”
// Timber
implementation ‘com.jakewharton.timber:timber:4.7.1’
// Notification Library
implementation “io.karn:notify:1.3.0”
// Easy Permissions
implementation ‘pub.devrel:easypermissions:3.0.0’
// Material Design
implementation ‘com.google.android.material:material:1.5.0-alpha02’
Step 3: Add a reference to the maven repository in the top-level build.gradle
allprojects {
   repositories {
       ...
       // For Notify library
       maven { url ‘https://jitpack.io’ }
   }
}
Step 4: Working with AndroidMenifest.xml
Make sure to add below permissions 
  <!– Required for 28 and below. –>
  <uses-permission android:name=”com.google.android.gms.permission.ACTIVITY_RECOGNITION” />
  <!– Required for 29+. –>
   <uses-permission android:name=”android.permission.ACTIVITY_RECOGNITION” />
<application >
....
<activity >
....
</activity>
<receiver
          android:name=”.ActivityTransitionReceiver”
          android:exported=”false”
          android:permission=”com.google.android.gms.permission.ACTIVITY_RECOGNITION”>
          <intent-filter>
              <action android:name=”action.TRANSITIONS_DATA” />
          </intent-filter>
      </receiver>
</application>
Step 5: Adding the UI of the application.
Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file.
XML
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.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">      <com.google.android.material.switchmaterial.SwitchMaterial        android:id="@+id/switchActivityTransition"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Activity Transition"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent" />  </androidx.constraintlayout.widget.ConstraintLayout>
Step 6: Create Constant.kt class and write all the required constants here
Kotlin
// declare all required constants at one placeobject Constants {    const val REQUEST_CODE_ACTIVITY_TRANSITION = 123    const val REQUEST_CODE_INTENT_ACTIVITY_TRANSITION = 122    const val ACTIVITY_TRANSITION_NOTIFICATION_ID = 111    const val ACTIVITY_TRANSITION_STORAGE = "ACTIVITY_TRANSITION_STORAGE"}
In Android, we have the Activity Recognition Client that wakes up your device at a regular interval and afterward gathers the information from the gadget’s sensor and after that this gathered information will be utilized to decide the Activities with the assistance of some Machine Learning calculation. You should simply utilize the Activity Recognition Client and the API will wrap up for you no compelling reason to learn ML.
 Following are the activities that can be detected by the Activity Recognition Client:
STILL: When the mobile device will be still when the user is either sitting at someplace or the mobile device is having no motion, then the Activity Recognition Client will detect the STILL activity.
ON_FOOT: When the mobile device is moving at a normal speed i.e. the user carrying the mobile device is either walking or running then the Activity Recognition Client will detect the ON_FOOT activity.
WALKING: This is a sub-activity of the ON_FOOT activity which is detected by the Activity Recognition Client when the user carrying the mobile device is walking.
RUNNING: This is also a sub-activity of ON_FOOT activity which is detected by the Activity Recognition Client when the user carrying the mobile device is running.
IN_VEHICLE: This activity is detected when the mobile device is in the bus or car or some other kind of vehicle or the user holding the mobile device is present in the vehicle.
ON_BICYCLE: When the device is on the bicycle or the user carrying the mobile is on a bicycle then this activity will be detected.
TILTING: When the mobile device is being lifted and is having some angle with the flat surface then the Activity Recognition Client will detect this activity.
UNKNOWN: The Activity Recognition Client will show this result when the device is unable to detect any activity on the mobile device.
Step 7: Create ActivityTransitionsUtil.kt class that will contain a list of activities types and transition types
To start receiving notifications about activity transitions we must build an ActivityTransitionRequest object that determines the type of activity and transition. For this, we must create a list of ActivityTransition objects and pass it to the ActivityTransitionRequest class. Below is the complete code of the ActivityTransitionsUtil.kt class. Comments are added inside the code to understand each line of the code.
Kotlin
import android.Manifestimport android.content.Contextimport android.os.Buildimport androidx.annotation.RequiresApiimport com.google.android.gms.location.ActivityTransitionimport com.google.android.gms.location.ActivityTransitionRequestimport com.google.android.gms.location.DetectedActivityimport pub.devrel.easypermissions.EasyPermissions  object ActivityTransitionsUtil {    private fun getTransitions(): MutableList<ActivityTransition> {          // List of activity transitions to track        val transitions = mutableListOf<ActivityTransition>()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.IN_VEHICLE)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.IN_VEHICLE)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.WALKING)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.WALKING)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.STILL)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.STILL)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.RUNNING)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)                .build()          transitions +=            ActivityTransition.Builder()                .setActivityType(DetectedActivity.RUNNING)                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)                .build()          return transitions    }      // pass the list of ActivityTransition objects to the ActivityTransitionRequest class    fun getActivityTransitionRequest() = ActivityTransitionRequest(getTransitions())      // ask to allow permissions    @RequiresApi(Build.VERSION_CODES.Q)    fun hasActivityTransitionPermissions(context: Context): Boolean =        EasyPermissions.hasPermissions(            context,            Manifest.permission.ACTIVITY_RECOGNITION        )      // types of activities    fun toActivityString(activity: Int): String {        return when (activity) {            DetectedActivity.STILL -> "STILL"            DetectedActivity.WALKING -> "WALKING"            DetectedActivity.IN_VEHICLE -> "IN VEHICLE"            DetectedActivity.RUNNING -> "RUNNING"            else -> "UNKNOWN"        }    }      // type of transitions    fun toTransitionType(transitionType: Int): String {        return when (transitionType) {            ActivityTransition.ACTIVITY_TRANSITION_ENTER -> "ENTER"            ActivityTransition.ACTIVITY_TRANSITION_EXIT -> "EXIT"            else -> "UNKNOWN"        }    }}
Step 8: Create ActivityTransitionReceiver.kt class which receives the activities and notifies the user’s state 
Below is the complete code of the ActivityTransitionReceiver.kt class. Comments are added inside the code to understand each line of the code.
Kotlin
import android.content.BroadcastReceiverimport android.content.Contextimport android.content.Intentimport android.widget.Toastimport com.google.android.gms.location.ActivityTransitionResultimport io.karn.notify.Notifyimport java.text.SimpleDateFormatimport java.util.*  class ActivityTransitionReceiver : BroadcastReceiver() {      override fun onReceive(context: Context, intent: Intent) {        if (ActivityTransitionResult.hasResult(intent)) {            val result = ActivityTransitionResult.extractResult(intent)            result?.let {                result.transitionEvents.forEach { event ->                    // Info about activity                    val info =                        "Transition: " + ActivityTransitionsUtil.toActivityString(event.activityType) +                                " (" + ActivityTransitionsUtil.toTransitionType(event.transitionType) + ")" + "   " +                                SimpleDateFormat("HH:mm:ss", Locale.US).format(Date())                    // notification details                    Notify                        .with(context)                        .content {                            title = "Activity Detected"                            text = "I can see you are in ${                                ActivityTransitionsUtil.toActivityString(                                    event.activityType                                )                            } state"                        }                        .show(id = Constants.ACTIVITY_TRANSITION_NOTIFICATION_ID)                    Toast.makeText(context, info, Toast.LENGTH_LONG).show()                }            }        }    }}
Step 9: Working with MainActivity.kt.Below is the code for MainActivity.kt 
Below is the complete code for the MainActivity.kt file. Comments are added inside the code to understand each line of the code.
Kotlin
import android.Manifestimport android.app.PendingIntentimport android.content.Intentimport android.content.SharedPreferencesimport android.os.Buildimport android.os.Bundleimport android.widget.Toastimport androidx.annotation.RequiresApiimport androidx.appcompat.app.AppCompatActivityimport com.gfg.article.activityrecognition.Constants.ACTIVITY_TRANSITION_STORAGEimport com.google.android.gms.location.ActivityRecognitionimport com.google.android.gms.location.ActivityRecognitionClientimport kotlinx.android.synthetic.main.activity_main.*import pub.devrel.easypermissions.AppSettingsDialogimport pub.devrel.easypermissions.EasyPermissions  class MainActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks {      lateinit var client: ActivityRecognitionClient    lateinit var storage: SharedPreferences      override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)          // The Activity Recognition Client returns a           // list of activities that a user might be doing        client = ActivityRecognition.getClient(this)                  // variable to check whether the user have already given the permissions        storage = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this)          // check switch is on/off        switchActivityTransition.isChecked = getSwitchState()          switchActivityTransition.setOnCheckedChangeListener { _, isChecked ->            if (isChecked) {                // check for devices with Android 10 (29+).                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q                    // check for permission                    && !ActivityTransitionsUtil.hasActivityTransitionPermissions(this)                ) {                    switchActivityTransition.isChecked = false                    // request for permission                    requestActivityTransitionPermission()                } else {                    // when permission is already allowed                    requestForUpdates()                }            } else {                saveSwitchState(false)                deregisterForUpdates()            }        }    }      // when permission is denied    @RequiresApi(Build.VERSION_CODES.Q)    override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {        // permission is denied permanently        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {            AppSettingsDialog.Builder(this).build().show()        } else {            requestActivityTransitionPermission()        }    }      // after giving permission    override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {        switchActivityTransition.isChecked = true        saveSwitchState(true)        requestForUpdates()    }      // request for permission    override fun onRequestPermissionsResult(        requestCode: Int,        permissions: Array<out String>,        grantResults: IntArray    ) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults)        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)    }      // To register for changes we have to also supply the requestActivityTransitionUpdates() method    // with the PendingIntent object that will contain an intent to the component    // (i.e. IntentService, BroadcastReceiver etc.) that will receive and handle updates appropriately.    private fun requestForUpdates() {        client            .requestActivityTransitionUpdates(                ActivityTransitionsUtil.getActivityTransitionRequest(),                getPendingIntent()            )            .addOnSuccessListener {                showToast("successful registration")            }            .addOnFailureListener {                showToast("Unsuccessful registration")            }    }      // Deregistering from updates    // call the removeActivityTransitionUpdates() method    // of the ActivityRecognitionClient and pass     // ourPendingIntent object as a parameter    private fun deregisterForUpdates() {        client            .removeActivityTransitionUpdates(getPendingIntent())            .addOnSuccessListener {                getPendingIntent().cancel()                showToast("successful deregistration")            }            .addOnFailureListener { e: Exception ->                showToast("unsuccessful deregistration")            }    }      // creates and returns the PendingIntent object which holds     // an Intent to an BroadCastReceiver class    private fun getPendingIntent(): PendingIntent {        val intent = Intent(this, ActivityTransitionReceiver::class.java)        return PendingIntent.getBroadcast(            this,            Constants.REQUEST_CODE_INTENT_ACTIVITY_TRANSITION,            intent,            PendingIntent.FLAG_UPDATE_CURRENT        )    }      // requesting for permission    @RequiresApi(Build.VERSION_CODES.Q)    private fun requestActivityTransitionPermission() {        EasyPermissions.requestPermissions(            this,            "You need to allow Activity Transition Permissions in order to recognize your activities",            Constants.REQUEST_CODE_ACTIVITY_TRANSITION,            Manifest.permission.ACTIVITY_RECOGNITION        )    }      private fun showToast(message: String) {        Toast.makeText(this, message, Toast.LENGTH_LONG)            .show()    }      // save switch state    private fun saveSwitchState(value: Boolean) {        storage            .edit()            .putBoolean(ACTIVITY_TRANSITION_STORAGE, value)            .apply()    }      // get the state of switch    private fun getSwitchState() = storage.getBoolean(ACTIVITY_TRANSITION_STORAGE, false)}
Now, run the app
Output:
When user walks
When user have no movement
Source Code: Click Here
Picked
TrueGeek-2021
Android
Kotlin
TrueGeek
Android
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Flutter - Custom Bottom Navigation Bar
Retrofit with Kotlin Coroutine in Android
GridView in Android with Example
How to Change the Background Color After Clicking the Button in Android?
Android Listview in Java with Example
Android UI Layouts
Kotlin Array
Retrofit with Kotlin Coroutine in Android
MVP (Model View Presenter) Architecture Pattern in Android with Example