Manual Tecnico
Manual Tecnico
A
caminar!"
Introducción
Este manual técnico proporciona una guía detallada sobre cómo se desarrolló la aplicación "!A
caminar!" utilizando Android Studio. La aplicación se centra en contar los pasos del usuario,
almacenar datos, utilizar la cámara para tomar fotos y vídeos, así como aprovechar los sensores del
móvil para el conteo de pasos en tiempo real. El desarrollo se realizó utilizando el lenguaje de
programación Kotlin.
</androidx.constraintlayout.widget.ConstraintLayout>
● MainActivity.kt: En este archivo se encuentra la lógica de la actividad principal de la
aplicación. Se encarga de inicializar los componentes de la interfaz de usuario, como los
botones flotantes y el sensor de pasos. Además, implementa métodos para contar los pasos
en tiempo real, guardar los pasos dados, tomar fotos y restablecer el contador.
package com.example.gfg
import android.content.Context
import android.content.Intent
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity(), SensorEventListener {
private var sensorManager: SensorManager? = null
private var running = false
private var totalSteps = 0f
private var stepsSinceOpen = 0f
findViewById<FloatingActionButton>(R.id.fab_save).setOnClickListener {
saveSteps()
}
findViewById<FloatingActionButton>(R.id.fab_history).setOnClickListener {
startActivity(Intent(this, HistoryActivity::class.java))
}
findViewById<FloatingActionButton>(R.id.fab_camera).setOnClickListener {
startActivity(Intent(this, CameraActivity::class.java))
}
findViewById<FloatingActionButton>(R.id.fab_reset).setOnClickListener {
resetSteps()
}
}
if (stepSensor == null) {
Toast.makeText(this, "No Step Sensor!", Toast.LENGTH_SHORT).show()
} else {
sensorManager?.registerListener(this, stepSensor,
SensorManager.SENSOR_DELAY_UI)
}
}
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="!Toma foto de tu actividad diaria!"
android:textSize="24sp"
android:textColor="@android:color/black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="350dp"
android:layout_height="350dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="@android:color/darker_gray"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/fab_camera"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintVertical_bias="0.35" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Take Photo"
android:src="@drawable/ic_camera"
app:layout_constraintBottom_toTopOf="@id/fab_back"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/fab_load"
android:layout_marginTop="16dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Load Image"
android:src="@drawable/ic_image"
app:layout_constraintBottom_toTopOf="@id/fab_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/fab_camera"
android:layout_marginTop="16dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Back"
android:src="@drawable/ic_back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.gfg
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
imageView = findViewById(R.id.imageView)
findViewById<FloatingActionButton>(R.id.fab_load).setOnClickListener {
openGallery()
}
findViewById<FloatingActionButton>(R.id.fab_camera).setOnClickListener {
openCamera()
}
findViewById<FloatingActionButton>(R.id.fab_back).setOnClickListener {
finish() // Regresa a la MainActivity
}
checkPermissions()
}
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE),
REQUEST_PERMISSION_CODE)
}
}
@Throws(IOException::class)
private fun createImageFile(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir
).apply {
currentPhotoPath = absolutePath
}
}
<ListView
android:id="@+id/listView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintBottom_toTopOf="@+id/btn_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:padding="16dp" />
<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.gfg
import android.widget.Button
import android.database.Cursor
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
if (cursor.moveToFirst()) {
do {
val steps = cursor.getInt(cursor.getColumnIndexOrThrow("steps"))
val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow("timestamp"))
val date = java.text.SimpleDateFormat("dd/MM/yyyy
HH:mm:ss").format(java.util.Date(timestamp))
stepList.add("Pasos: $steps, Fecha: $date")
} while (cursor.moveToNext())
}
● file_paths.xml: Este archivo define la ruta de almacenamiento para las imágenes capturadas
por la cámara.
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="my_images"
path="Pictures/" />
</paths>
package com.example.gfg
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
companion object {
private const val DATABASE_NAME = "steps.db"
private const val DATABASE_VERSION = 1
private const val TABLE_STEPS = "steps"
private const val COLUMN_ID = "id"
private const val COLUMN_STEPS = "steps"
private const val COLUMN_TIMESTAMP = "timestamp"
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GFG"
tools:targetApi="31">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".CameraActivity" android:exported="true"></activity>
<activity android:name=".HistoryActivity" android:exported="true"></activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.gfg.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>
Evaluación de la Aplicación
La aplicación "!A caminar!" cumple con los requisitos establecidos en la fase de desarrollo:
Conclusiones
La combinación de diseño de interfaz intuitivo, funcionalidades clave como el contador de pasos y la
integración de la cámara hacen que "!A caminar!" sea una aplicación útil para motivar a los usuarios
a mantener un estilo de vida activo y saludable.