Work with fitness goals

Goals are targets in the Google Fit app that users can set for themselves. They help motivate users to stay active every day. From within their profile, users can adjust how many Steps and Heart Points they want to aim for each day. The Fit platform records their goals and tracks their daily activity against these.

Create a better user experience with goals

Your app can read a user's goals to keep track of their personal targets. This can help create a more engaging experience. To start, use the GoalsClient client to read a user's Steps and Heart Points goals. Then use the HistoryClient client to check how close they are to those goals.

Use this data to help users switch between Google Fit and your app seamlessly, and get consistent information across both apps about their progress towards their fitness goals.

Motivate users to reach their daily goals by giving them updates and insights related to their progress.

Read a goal

The following example shows how to create a new Fitness client and get the user's Heart Points goal, or null if they don't have a goal set.

Kotlin

 private 
  
 val 
  
 fitnessOptions 
 : 
  
 FitnessOptions 
  
 by 
  
 lazy 
  
 { 
  
 FitnessOptions 
 . 
 builder 
 () 
  
 . 
 addDataType 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 , 
  
 FitnessOptions 
 . 
 ACCESS_READ 
 ) 
  
 . 
 build 
 () 
 } 
 private 
  
 val 
  
 goalsReadRequest 
 : 
  
 GoalsReadRequest 
  
 by 
  
 lazy 
  
 { 
  
 GoalsReadRequest 
 . 
 Builder 
 () 
  
 . 
 addDataType 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 ) 
  
 . 
 build 
 () 
 } 
 private 
  
 fun 
  
 getGoogleAccount 
 (): 
  
 GoogleSignInAccount 
  
 = 
  
 GoogleSignIn 
 . 
 getAccountForExtension 
 ( 
 requireContext 
 (), 
  
 fitnessOptions 
 ) 
 private 
  
 fun 
  
 readGoals 
 () 
  
 { 
  
 Fitness 
 . 
 getGoalsClient 
 ( 
 requireContext 
 (), 
  
 getGoogleAccount 
 ()) 
  
 . 
 readCurrentGoals 
 ( 
 goalsReadRequest 
 ) 
  
 . 
 addOnSuccessListener 
  
 { 
  
 goals 
  
 - 
>  
 // There should be at most one heart points goal currently. 
  
 goals 
 . 
 firstOrNull 
 () 
 ?. 
 apply 
  
 { 
  
 // What is the value of the goal 
  
 val 
  
 goalValue 
  
 = 
  
 metricObjective 
 . 
 value 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Goal value: 
 $ 
 goalValue 
 " 
 ) 
  
 // How is the goal measured? 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Objective: 
 $ 
 objective 
 " 
 ) 
  
 // How often does the goal repeat? 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Recurrence: 
 $ 
 recurrenceDetails 
 " 
 ) 
  
 } 
  
 } 
 } 
 private 
  
 val 
  
 Goal 
 . 
 objective 
 : 
  
 String 
  
 get 
 () 
  
 = 
  
 when 
  
 ( 
 objectiveType 
 ) 
  
 { 
  
 OBJECTIVE_TYPE_DURATION 
  
 - 
>  
 "Duration (s): 
 ${ 
 durationObjective 
 . 
 getDuration 
 ( 
 TimeUnit 
 . 
 SECONDS 
 ) 
 } 
 " 
  
 OBJECTIVE_TYPE_FREQUENCY 
  
 - 
>  
 "Frequency : 
 ${ 
 frequencyObjective 
 . 
 frequency 
 } 
 " 
  
 OBJECTIVE_TYPE_METRIC 
  
 - 
>  
 "Metric : 
 ${ 
 metricObjective 
 . 
 dataTypeName 
 } 
 - 
 ${ 
 metricObjective 
 . 
 value 
 } 
 " 
  
 else 
  
 - 
>  
 "Unknown objective" 
  
 } 
 private 
  
 val 
  
 Goal 
 . 
 recurrenceDetails 
 : 
  
 String 
  
 get 
 () 
  
 = 
  
 recurrence 
 ?. 
 let 
  
 { 
  
 val 
  
 period 
  
 = 
  
 when 
  
 ( 
 it 
 . 
 unit 
 ) 
  
 { 
  
 Recurrence 
 . 
 UNIT_DAY 
  
 - 
>  
 "days" 
  
 Recurrence 
 . 
 UNIT_WEEK 
  
 - 
>  
 "weeks" 
  
 Recurrence 
 . 
 UNIT_MONTH 
  
 - 
>  
 "months" 
  
 else 
  
 - 
>  
 "Unknown" 
  
 } 
  
 "Every 
 ${ 
 recurrence 
 !! 
 . 
 count 
 } 
  
 $ 
 period 
 " 
  
 } 
  
 ?: 
  
 "Does not repeat" 

Java

 private 
  
 final 
  
 FitnessOptions 
  
 fitnessOptions 
  
 = 
  
 FitnessOptions 
 . 
 builder 
 () 
  
 . 
 addDataType 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 , 
  
 FitnessOptions 
 . 
 ACCESS_READ 
 ) 
  
 . 
 build 
 (); 
 private 
  
 final 
  
 GoalsReadRequest 
  
 goalsReadRequest 
  
 = 
  
 new 
  
 GoalsReadRequest 
 . 
 Builder 
 () 
  
 . 
 addDataType 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 ) 
  
 . 
 build 
 (); 
 private 
  
 GoogleSignInAccount 
  
 getGoogleAccount 
 () 
  
 { 
  
 GoogleSignIn 
 . 
 getAccountForExtension 
 ( 
 getApplicationContext 
 (), 
  
 fitnessOptions 
 ); 
 } 
 private 
  
 void 
  
 readGoals 
 () 
  
 { 
  
 Fitness 
 . 
 getGoalsClient 
 ( 
 getApplicationContext 
 (), 
  
 getGoogleAccount 
 ()) 
  
 . 
 readCurrentGoals 
 ( 
 goalsReadRequest 
 ) 
  
 . 
 addOnSuccessListener 
 ( 
 goals 
  
 - 
>  
 { 
  
 // There should be at most one heart points goal currently. 
  
 Optional<Goal> 
  
 optionalGoal 
  
 = 
  
 goals 
 . 
 stream 
 (). 
 findFirst 
 (); 
  
 if 
  
 ( 
 optionalGoal 
 . 
 isPresent 
 ()) 
  
 { 
  
 // What is the value of the goal 
  
 double 
  
 goalValue 
  
 = 
  
 optionalGoal 
 . 
 get 
 (). 
 getMetricObjective 
 (). 
 getValue 
 (); 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Goal value: $goalValue" 
 ); 
  
 // How is the goal measured? 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Objective: ${getObjective(optionalGoal.get())}" 
 ); 
  
 // How often does the goal repeat? 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Recurrence: ${getRecurrenceDetails(optionalGoal.get())}" 
 ); 
  
 } 
  
 }); 
 } 
 private 
  
 String 
  
 getObjective 
 ( 
 Goal 
  
 goal 
 ) 
  
 { 
  
 switch 
  
 ( 
 goal 
 . 
 getObjectiveType 
 ()) 
  
 { 
  
 case 
  
 OBJECTIVE_TYPE_DURATION 
 : 
  
 return 
  
 "Duration (s): ${goal.getDurationObjective().getDuration(TimeUnit.SECONDS)}" 
 ; 
  
 case 
  
 OBJECTIVE_TYPE_FREQUENCY 
 : 
  
 return 
  
 "Frequency : ${goal.getFrequencyObjective().getFrequency()}" 
 ; 
  
 case 
  
 OBJECTIVE_TYPE_METRIC 
 : 
  
 return 
  
 "Metric : ${goal.getMetricObjective().getDataTypeName()} - ${goal.getMetricObjective().getValue()}" 
 ; 
  
 default 
 : 
  
 return 
  
 "Unknown objective" 
 ; 
  
 } 
 } 
 private 
  
 String 
  
 getRecurrenceDetails 
 ( 
 Goal 
  
 goal 
 ) 
  
 { 
  
 Goal 
 . 
 Recurrence 
  
 recurrence 
  
 = 
  
 goal 
 . 
 getRecurrence 
 (); 
  
 if 
  
 ( 
 recurrence 
  
 == 
  
 null 
 ) 
  
 { 
  
 return 
  
 "Does not repeat" 
 ; 
  
 } 
  
 StringBuilder 
  
 recurrenceMessage 
  
 = 
  
 new 
  
 StringBuilder 
 ( 
 "Every ${recurrence.getCount()}" 
 ); 
  
 switch 
  
 ( 
 recurrence 
 . 
 getUnit 
 ()) 
  
 { 
  
 case 
  
 UNIT_DAY 
 : 
  
 recurrenceMessage 
 . 
 append 
 ( 
 "days" 
 ); 
  
 break 
 ; 
  
 case 
  
 UNIT_WEEK 
 : 
  
 recurrenceMessage 
 . 
 append 
 ( 
 "weeks" 
 ); 
  
 break 
 ; 
  
 case 
  
 UNIT_MONTH 
 : 
  
 recurrenceMessage 
 . 
 append 
 ( 
 "months" 
 ); 
  
 break 
 ; 
  
 default 
 : 
  
 recurrenceMessage 
 . 
 delete 
 ( 
 0 
 , 
  
 recurrenceMessage 
 . 
 length 
 ()); 
  
 recurrenceMessage 
 . 
 append 
 ( 
 "Unknown" 
 ); 
  
 break 
 ; 
  
 } 
  
 return 
  
 recurrenceMessage 
 . 
 toString 
 (); 
 } 

Check progress

After you have the user's Heart Points goal, you can use the HistoryClient to check their progress. The following example shows how to check how many Heart Points the user has.

Kotlin

 val 
  
 current 
  
 = 
  
 Calendar 
 . 
 getInstance 
 () 
 val 
  
 request 
  
 = 
  
 DataReadRequest 
 . 
 Builder 
 () 
  
 . 
 read 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 ) 
  
 . 
 setTimeRange 
 ( 
  
 goal 
 . 
 getStartTime 
 ( 
 current 
 , 
  
 TimeUnit 
 . 
 NANOSECONDS 
 ), 
  
 goal 
 . 
 getEndTime 
 ( 
 current 
 , 
  
 TimeUnit 
 . 
 NANOSECONDS 
 ), 
  
 TimeUnit 
 . 
 NANOSECONDS 
  
 ) 
  
 . 
 build 
 () 
 Fitness 
 . 
 getHistoryClient 
 ( 
 requireContext 
 (), 
  
 getGoogleAccount 
 ()) 
  
 . 
 readData 
 ( 
 request 
 ) 
  
 . 
 addOnSuccessListener 
  
 { 
  
 response 
  
 - 
>  
 val 
  
 heartPointsSet 
  
 = 
  
 response 
 . 
 dataSets 
 . 
 first 
 () 
  
 val 
  
 totalHeartPoints 
  
 = 
  
 heartPointsSet 
 . 
 dataPoints 
 . 
 sumBy 
  
 { 
  
 it 
 . 
 getValue 
 ( 
 Field 
 . 
 FIELD_INTENSITY 
 ). 
 asFloat 
 (). 
 toInt 
 () 
  
 } 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Total heart points: 
 $ 
 totalHeartPoints 
 " 
 ) 
  
 } 

Java

 Calendar 
  
 current 
  
 = 
  
 Calendar 
 . 
 getInstance 
 (); 
 DataReadRequest 
  
 request 
  
 = 
  
 new 
  
 DataReadRequest 
 . 
 Builder 
 () 
  
 . 
 read 
 ( 
 DataType 
 . 
 TYPE_HEART_POINTS 
 ) 
  
 . 
 setTimeRange 
 ( 
  
 goal 
 . 
 getStartTime 
 ( 
 current 
 , 
  
 TimeUnit 
 . 
 NANOSECONDS 
 ), 
  
 goal 
 . 
 getEndTime 
 ( 
 current 
 , 
  
 TimeUnit 
 . 
 NANOSECONDS 
 ), 
  
 TimeUnit 
 . 
 NANOSECONDS 
  
 ) 
  
 . 
 build 
 (); 
 Fitness 
 . 
 getHistoryClient 
 ( 
 getApplicationContext 
 (), 
  
 getGoogleAccount 
 ()) 
  
 . 
 readData 
 ( 
 request 
 ) 
  
 . 
 addOnSuccessListener 
 ( 
 response 
  
 - 
>  
 { 
  
 Optional<DataSet> 
  
 heartPointsSet 
  
 = 
  
 response 
 . 
 getDataSets 
 (). 
 stream 
 (). 
 findFirst 
 (); 
  
 if 
  
 ( 
 heartPointsSet 
 . 
 isPresent 
 ()) 
  
 { 
  
 int 
  
 totalHeartPoints 
  
 = 
  
 0 
 ; 
  
 for 
  
 ( 
 DataPoint 
  
 dp 
  
 : 
  
 heartPointsSet 
 . 
 get 
 (). 
 getDataPoints 
 ()) 
  
 { 
  
 totalHeartPoints 
  
 += 
  
 ( 
 int 
 ) 
  
 dp 
 . 
 getValue 
 ( 
 Field 
 . 
 FIELD_INTENSITY 
 ). 
 asFloat 
 (); 
  
 } 
  
 Log 
 . 
 i 
 ( 
 TAG 
 , 
  
 "Total heart points: $totalHeartPoints" 
 ); 
  
 } 
  
 }); 

Calculate progress as a percentage

If you divide the total from the check progress example by the target in the read a goal example, you can calculate the progress towards the goal as a percentage.

Kotlin

 private 
  
 fun 
  
 calculateProgressPercentage 
 ( 
 goal 
 : 
  
 Goal 
 , 
  
 response 
 : 
  
 DataReadResponse 
 ): 
  
 Double 
  
 { 
  
 val 
  
 goalValue 
  
 = 
  
 goal 
 . 
 metricObjective 
 . 
 value 
  
 val 
  
 currentTotal 
  
 = 
  
 response 
 . 
 dataSets 
 . 
 first 
 (). 
 dataPoints 
 . 
 sumBy 
  
 { 
  
 it 
 . 
 getValue 
 ( 
 Field 
 . 
 FIELD_INTENSITY 
 ). 
 asFloat 
 (). 
 toInt 
 () 
  
 } 
  
 return 
  
 ( 
 currentTotal 
 . 
 div 
 ( 
 goalValue 
 )). 
 times 
 ( 
 100.0 
 ) 
 } 

Java

 private 
  
 double 
  
 calculateProgressPercentage 
 ( 
 Goal 
  
 goal 
 , 
  
 DataReadResponse 
  
 response 
 ) 
  
 { 
  
 double 
  
 goalValue 
  
 = 
  
 goal 
 . 
 getMetricObjective 
 (). 
 getValue 
 (); 
  
 Optional<DataSet> 
  
 firstDataSet 
  
 = 
  
 response 
 . 
 getDataSets 
 (). 
 stream 
 (). 
 findFirst 
 (); 
  
 if 
  
 ( 
 ! 
 ( 
 firstDataSet 
 . 
 isPresent 
 ())) 
  
 { 
  
 return 
  
 NaN 
 ; 
  
 } 
  
 double 
  
 currentTotal 
  
 = 
  
 0 
 ; 
  
 for 
  
 ( 
 DataPoint 
  
 dp 
  
 : 
  
 firstDataSet 
 . 
 get 
 (). 
 getDataPoints 
 ()) 
  
 { 
  
 currentTotal 
  
 += 
  
 ( 
 int 
 ) 
 dp 
 . 
 getValue 
 ( 
 Field 
 . 
 FIELD_INTENSITY 
 ). 
 asFloat 
 (); 
  
 } 
  
 return 
  
 ( 
 currentTotal 
  
 / 
  
 goalValue 
 ) 
  
 * 
  
 100.0 
 ; 
 } 
Create a Mobile Website
View Site in Mobile | Classic
Share by: