Cómo trabajar con sesiones

Las sesiones representan un intervalo durante el cual los usuarios realizan una actividad de entrenamiento. La API de Sessions permite que tu app cree sesiones en la tienda de entrenamiento.

Para las actividades de entrenamiento en curso en las que el usuario notifica a tu app cuando inicia y finaliza una actividad de entrenamiento, puedes crear sesiones en tiempo real.

También puedes insertar una sesión en la tienda de entrenamiento después de que esta finalice o cuando importes datos y sesiones fuera de Google Fit.

Crea sesiones en tiempo real

Para crear sesiones de actividades físicas en curso, completa los siguientes pasos:

  1. Suscríbete a los datos de entrenamiento con el método RecordingClient.subscribe.

  2. Inicia una sesión con el método SessionsClient.startSession cuando el usuario inicie la actividad de entrenamiento.

  3. Detén la sesión con el método SessionsClient.stopSession cuando el usuario finalice la actividad de entrenamiento.

  4. Anula la suscripción a los datos de entrenamiento que ya no te interesan mediante el método RecordingClient.unsubscribe.

Iniciar una sesión

Para iniciar una sesión en tu app, usa el método SessionsClient.startSession:

Kotlin

// 1. Subscribe to fitness data
// 2. Create a session object
// (provide a name, identifier, description, activity and start time)
val session = Session.Builder()
    .setName(sessionName)
    .setIdentifier("UniqueIdentifierHere")
    .setDescription("Morning run")
    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .build()

// 3. Use the Sessions client to start a session:
Fitness.getSessionsClient(this, googleSigninAccount)
    .startSession(session)
    .addOnSuccessListener {
        Log.i(TAG, "Session started successfully!")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was an error starting the session", e)
    }

Java

// 1. Subscribe to fitness data
// 2. Create a session object
// (provide a name, identifier, description, activity and start time)
Session session = new Session.Builder()
        .setName(sessionName)
        .setIdentifier("UniqueIdentifierHere")
        .setDescription("Morning run")
        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .build();

// 3. Use the Sessions client to start a session:
Fitness.getSessionsClient(this, googleSigninAccount)
        .startSession(session)
        .addOnSuccessListener(unused ->
                Log.i(TAG, "Session started successfully!"))
        .addOnFailureListener(e ->
                Log.w(TAG, "There was an error starting the session", e));

Detener una sesión

Para detener una sesión en tu app, usa el método SessionsClient.stopSession:

Kotlin

// Invoke the SessionsClient with the session identifier
Fitness.getSessionsClient(this, googleSigninAccount)
    .stopSession(session.getIdentifier())
    .addOnSuccessListener {
        Log.i(TAG, "Session stopped successfully!")

        // Now unsubscribe from the fitness data (see
        // Recording Fitness data)
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was an error stopping the session", e)
    }

Java

// Invoke the SessionsClient with the session identifier
Fitness.getSessionsClient(this, googleSigninAccount)
        .stopSession(session.getIdentifier())
        .addOnSuccessListener (unused -> {
            Log.i(TAG, "Session stopped successfully!");
            // Now unsubscribe from the fitness data (see
            // Recording Fitness data)
        })
        .addOnFailureListener(e ->
                Log.w(TAG, "There was an error stopping the session", e));

La sesión resultante tiene los siguientes parámetros:

  • Hora de inicio: La hora en la que la app llamó al método SessionsClient.startSession.

  • Hora de finalización: La hora a la que la app llamó al método SessionsClient.stopSession

  • Nombre: el nombre del objeto Session que pasas a SessionsClient.startSession

Insertar sesiones en la tienda de entrenamiento

Para insertar sesiones con los datos recopilados anteriormente, haz lo siguiente:

  1. Crea un objeto Session que especifique un intervalo de tiempo y otra información requerida.

  2. Crea un SessionInsertRequest con la sesión.

  3. De forma opcional, puedes agregar conjuntos de datos y agregar datos.

  4. Inserta la sesión con el método SessionsClient.insertSession.

Cómo insertar una sesión

Para insertar datos de entrenamiento que contengan metadatos de sesión en el historial de entrenamiento del usuario, primero crea una instancia de SessionInsertRequest:

Kotlin

// Create a session with metadata about the activity.
val session = Session.Builder()
    .setName(SAMPLE_SESSION_NAME)
    .setIdentifier("UniqueIdentifierHere")
    .setDescription("Long run around Shoreline Park")

    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .setEndTime(endTime, TimeUnit.MILLISECONDS)
    .build()

// Build a session insert request
val insertRequest = SessionInsertRequest.Builder()
    .setSession(session)
    // Optionally add DataSets for this session.
    .addDataSet(dataset)
    .build()

Java

// Create a session with metadata about the activity.
Session session = new Session.Builder()
        .setName(SAMPLE_SESSION_NAME)
        .setIdentifier("UniqueIdentifierHere")
        .setDescription("Long run around Shoreline Park")

        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .setEndTime(endTime, TimeUnit.MILLISECONDS)
        .build();

// Build a session insert request
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
        .setSession(session)
        // Optionally add DataSets for this session.
        .addDataSet(dataset)
        .build();

La clase SessionInsertRequest proporciona métodos convenientes para insertar datos en el historial de entrenamiento y crear una sesión en la misma llamada a SessionsClient.insertSession. Los conjuntos de datos, si los hay, se insertan como si hubieras llamado primero al método HistoryClient.insertData y, luego, se creó la sesión.

Kotlin

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
    .insertSession(insertRequest)
    .addOnSuccessListener {
        Log.i(TAG, "Session insert was successful!")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was a problem inserting the session: ", e)
    }

Java

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
        .insertSession(insertRequest)
        .addOnSuccessListener (unused ->
                Log.i(TAG, "Session insert was successful!"))
        .addOnFailureListener(e ->
        Log.w(TAG, "There was a problem inserting the session: ", e));

Cómo insertar segmentos de actividad

Los datos del segmento de actividad en Google Fit indican qué actividad física realizan los usuarios durante un intervalo determinado. Los datos del segmento de actividad son del tipo com.google.activity.segment (TYPE_ACTIVITY_SEGMENT) y son particularmente útiles para admitir pausas durante los entrenamientos.

Por ejemplo, si creas una sesión de ejecución de 30 minutos con el método Session.Builder.setActivity(), pero el usuario se toma un intervalo de 10 minutos, tu app mostrará incorrectamente que el usuario se ejecutó durante 30 minutos. Si tu app puede detectar si el usuario estaba caminando o corriendo, los datos del segmento de actividad le permiten indicar que se ejecutó 10 minutos, 10 minutos y, luego, 10 minutos adicionales. Otras apps también pueden informar la actividad correctamente si observan los datos del segmento de actividad que insertas.

Para agregar datos del segmento de actividad a una sesión, crea un conjunto de datos que contenga puntos de tipo com.google.activity.segment. Cada uno de estos puntos representa un intervalo de tiempo continuo durante el cual el usuario realizó un solo tipo de actividad.

El ejemplo anterior de carreras y caminatas requeriría tres puntos de segmento de actividad: uno para correr durante los primeros 10 minutos, uno para caminar durante los siguientes 10 minutos y otro para correr durante los últimos 10 minutos.

Kotlin

// Create a DataSet of ActivitySegments to indicate the runner walked for
// 10 minutes in the middle of a run.
val activitySegmentDataSource = DataSource.Builder()
    .setAppPackageName(this.packageName)
    .setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
    .setStreamName(SAMPLE_SESSION_NAME + "-activity segments")
    .setType(DataSource.TYPE_RAW)
    .build()

val firstRunningDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
    .setTimeInterval(startTime, startWalkTime, TimeUnit.MILLISECONDS)
    .build()

val walkingDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.WALKING)
    .setTimeInterval(startWalkTime, endWalkTime, TimeUnit.MILLISECONDS)
    .build()

val secondRunningDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
    .setTimeInterval(endWalkTime, endTime, TimeUnit.MILLISECONDS)
    .build()

val activitySegments = DataSet.builder(activitySegmentDataSource)
    .addAll(listOf(firstRunningDp, walkingDp, secondRunningDp))
    .build()

// Create a session with metadata about the activity.
val session = Session.Builder()
    .setName(SAMPLE_SESSION_NAME)
    .setDescription("Long run around Shoreline Park")
    .setIdentifier("UniqueIdentifierHere")
    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .setEndTime(endTime, TimeUnit.MILLISECONDS)
    .build()

// Build a session insert request
val insertRequest = SessionInsertRequest.Builder()
    .setSession(session)
    .addDataSet(activitySegments)
    .build()

Java

// Create a DataSet of ActivitySegments to indicate the runner walked for
// 10 minutes in the middle of a run.
DataSource activitySegmentDataSource = new DataSource.Builder()
        .setAppPackageName(getPackageName())
        .setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
        .setStreamName(SAMPLE_SESSION_NAME + "-activity segments")
        .setType(DataSource.TYPE_RAW)
        .build();

DataPoint firstRunningDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
        .setTimeInterval(startTime, startWalkTime, TimeUnit.MILLISECONDS)
        .build();

DataPoint walkingDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.WALKING)
        .setTimeInterval(startWalkTime, endWalkTime, TimeUnit.MILLISECONDS)
        .build();

DataPoint secondRunningDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
        .setTimeInterval(endWalkTime, endTime, TimeUnit.MILLISECONDS)
        .build();

DataSet activitySegments = DataSet.builder(activitySegmentDataSource)
        .addAll(Arrays.asList(firstRunningDp, walkingDp, secondRunningDp))
        .build();

// Create a session with metadata about the activity.
Session session = new Session.Builder()
        .setName(SAMPLE_SESSION_NAME)
        .setDescription("Long run around Shoreline Park")
        .setIdentifier("UniqueIdentifierHere")
        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .setEndTime(endTime, TimeUnit.MILLISECONDS)
        .build();

// Build a session insert request
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
        .setSession(session)
        .addDataSet(activitySegments)
        .build();

Leer datos de entrenamiento mediante sesiones

La API de sesiones te permite obtener una lista de sesiones de la tienda de entrenamiento que coinciden con algunos criterios. Por ejemplo, puedes obtener todas las sesiones contenidas en un intervalo de tiempo o puedes obtener una sesión en particular por nombre o ID. También puedes especificar si te interesan las sesiones creadas por tu app o por cualquier app.

Para obtener una lista de sesiones que coincidan con algunos criterios, primero crea una instancia de SessionReadRequest:

Kotlin

// Use a start time of 1 week ago and an end time of now.
val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
val startTime = endTime.minusWeeks(1)

// Build a session read request
val readRequest = SessionReadRequest.Builder()
    .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
    .read(DataType.TYPE_SPEED)
    .setSessionName(SAMPLE_SESSION_NAME)
    .build()

Java

// Use a start time of 1 week ago and an end time of now.
ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
ZonedDateTime startTime = endTime.minusWeeks(1)

// Build a session read request
SessionReadRequest readRequest = new SessionReadRequest.Builder()
        .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
        .read(DataType.TYPE_SPEED)
        .setSessionName(SAMPLE_SESSION_NAME)
        .build();

Luego, usa el método SessionsClient.readSession:

Kotlin

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
    .readSession(readRequest)
    .addOnSuccessListener { response ->
        // Get a list of the sessions that match the criteria to check the result.
        val sessions = response.sessions
        Log.i(TAG, "Number of returned sessions is: ${sessions.size}")
        for (session in sessions) {
            // Process the session
            dumpSession(session)

            // Process the data sets for this session
            val dataSets = response.getDataSet(session)
            for (dataSet in dataSets) {
                // ...
            }
        }
    }
    .addOnFailureListener { e ->
        Log.w(TAG,"Failed to read session", e)
    }

Java

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
        .readSession(readRequest)
        .addOnSuccessListener(response -> {
            // Get a list of the sessions that match the criteria to check the
            // result.
            List<Session> sessions = response.getSessions();
            Log.i(TAG, "Number of returned sessions is: ${sessions.size}");
            for (Session session : sessions) {
                // Process the session
                dumpSession(session);

                // Process the data sets for this session
                List<DataSet> dataSets = response.getDataSet(session);
                for (DataSet dataSet : dataSets) {
                    // ...
                }
            }
        })
        .addOnFailureListener(e ->
                Log.w(TAG,"Failed to read session", e));

Cómo leer datos de sueño mediante sesiones

Las sesiones de sueño se tratan como otras sesiones de actividad. De forma predeterminada, las respuestas de lectura solo contienen sesiones de actividad, no sesiones de sueño.

Para incluir sesiones de sueño, usa el método includeSleepSessions cuando compiles tu SessionReadRequest. Para incluir actividades y sesiones, usa includeSleepSessions y includeActivitySessions.

Mostrar sesiones en otras apps

Para mostrar a los usuarios una vista más detallada de una sesión en particular en una app diferente, tu app puede invocar un intent que contiene la información de la sesión. Puedes especificar una app en particular, como la app que creó la sesión. O bien, en caso de que la app que creó la sesión no esté instalada en el dispositivo, puedes permitir que cualquier app que pueda mostrar actividad de entrenamiento responda al intent.

Si quieres crear un intent para mostrar datos de sesión en una app diferente, usa la clase SessionsApi.ViewIntentBuilder:

Kotlin

// Pass your activity object to the constructor
val intent = SessionsApi.ViewIntentBuilder(this)
    .setPreferredApplication("com.example.someapp") // optional
    .setSession(session)
    .build()

// Invoke the intent
startActivity(intent)

Java

// Pass your activity object to the constructor
Intent intent = new SessionsApi.ViewIntentBuilder(this)
        .setPreferredApplication("com.example.someapp") // optional
        .setSession(session)
        .build();

// Invoke the intent
startActivity(intent);

Recibe intents de otras apps

Si quieres registrar tu app para recibir intents de otras apps de salud y bienestar, declara en el manifiesto un filtro de intents similar al siguiente:

<intent-filter>
    <action android:name="vnd.google.fitness.VIEW"/>
    <data android:mimeType="vnd.google.fitness.session/running"/>
</intent-filter>

Cada intent que tu app recibe de Google Fit consiste en una sola actividad, pero puedes filtrar por varios tipos de MIME en un solo filtro de intents. El filtro de intents de tu app debe incluir todas las actividades que admite.

Los intents de entrenamiento incluyen los siguientes elementos adicionales:

  • vnd.google.gms.fitness.start_time
  • vnd.google.gms.fitness.end_time
  • vnd.google.gms.fitness.session

Puedes obtener datos de estos elementos adicionales de la siguiente manera:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    val supportedType = Session.getMimeType(FitnessActivities.RUNNING)

    if (Intent.ACTION_VIEW == intent.action && supportedType == intent.type) {
        // Get the intent extras
        val startTime = Fitness.getStartTime(intent, TimeUnit.MILLISECONDS);
        val endTime = Fitness.getEndTime(intent, TimeUnit.MILLISECONDS)
        val session = Session.extract(intent)
    }
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    String supportedType = Session.getMimeType(FitnessActivities.RUNNING);

    if (Intent.ACTION_VIEW.equals(getIntent().getAction()) && supportedType.equals(getIntent().getType())) {
        // Get the intent extras
        long startTime = Fitness.getStartTime(getIntent(), TimeUnit.MILLISECONDS);
        long endTime = Fitness.getEndTime(getIntent(), TimeUnit.MILLISECONDS);
        Session session = Session.extract(getIntent());
    }
}