0% found this document useful (0 votes)
23 views16 pages

Dosecare

The document contains the Android manifest and code for a medication reminder application called DoseCare. It includes features for adding and removing pill reminders, setting alarms, and managing a local database of pills. The application also handles permissions for notifications and alarm scheduling, and provides a user interface for managing reminders and viewing scheduled pills.

Uploaded by

itsmeankit8920
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views16 pages

Dosecare

The document contains the Android manifest and code for a medication reminder application called DoseCare. It includes features for adding and removing pill reminders, setting alarms, and managing a local database of pills. The application also handles permissions for notifications and alarm scheduling, and provides a user interface for managing reminders and viewing scheduled pills.

Uploaded by

itsmeankit8920
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

<manifest xmlns:android="http://schemas.android.

com/apk/res/android"
package="com.ankit.dosecare">

<!-- Required Permissions -->


<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>

<application
android:allowBackup="true"
android:theme="@style/Theme.DoseCare"
android:usesCleartextTraffic="true"
android:label="@string/app_name">

<!-- Main Activity (Launcher) -->


<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>

<!-- Other Activities -->


<activity android:name=".AddReminderActivity"/>
<activity android:name=".ScheduleActivity"/>

<!-- Alarm Receiver (Handles Alarms & Reboot) -->


<receiver android:name=".AlarmReceiver"
android:exported="false"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>

<!-- Required for AlarmManager -->


<service android:name=".AlarmService"
android:permission="android.permission.FOREGROUND_SERVICE"
android:exported="false"/>

</application>

</manifest>
package com.ankit.dosecare

import android.app.AlarmManager
import android.app.PendingIntent
import android.app.TimePickerDialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.ankit.dosecare.database.Pill
import com.ankit.dosecare.database.PillDatabase
import com.ankit.dosecare.databinding.ActivityAddReminderBinding
import java.util.*

class AddReminderActivity : AppCompatActivity() {

private lateinit var binding: ActivityAddReminderBinding


private lateinit var database: PillDatabase
private var selectedHour = 0
private var selectedMinute = 0

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
binding = ActivityAddReminderBinding.inflate(layoutInflater)
setContentView(binding.root)

database = PillDatabase.getDatabase(this)

// Time Picker with AM/PM


binding.etPillTime.setOnClickListener {
val calendar = Calendar.getInstance()
val hour = calendar.get(Calendar.HOUR_OF_DAY)
val minute = calendar.get(Calendar.MINUTE)

val timePicker = TimePickerDialog(this, { _, hourOfDay, minute ->


selectedHour = hourOfDay
selectedMinute = minute

val amPm = if (hourOfDay < 12) "AM" else "PM"


val displayHour = if (hourOfDay % 12 == 0) 12 else hourOfDay % 12
binding.etPillTime.setText(String.format("%02d:%02d %s", displayHour, minute, amPm))
}, hour, minute, false)

timePicker.show()
}

binding.btnSaveReminder.setOnClickListener {
val pillName = binding.etPillName.text.toString().trim()

if (pillName.isNotEmpty()) {
val pillTime = String.format("%02d:%02d", selectedHour, selectedMinute)
val pill = Pill(0, pillName, "500mg", pillTime)

Thread {
database.pillDao().insertPill(pill)
runOnUiThread {
setAlarm(selectedHour, selectedMinute)
Toast.makeText(this, "Reminder Added", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}.start()
} else {
Toast.makeText(this, "Enter Pill Name", Toast.LENGTH_SHORT).show()
}
}

// Remove Reminder
binding.btnRemoveReminder.setOnClickListener {
val pillName = binding.etPillName.text.toString().trim()
if (pillName.isNotEmpty()) {
Thread {
val pill = database.pillDao().getPillByName(pillName)
if (pill != null) {
database.pillDao().deletePill(pill)
cancelAlarm()
runOnUiThread {
Toast.makeText(this, "Reminder Removed", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
} else {
runOnUiThread {
Toast.makeText(this, "Pill Not Found", Toast.LENGTH_SHORT).show()
}
}
}.start()
} else {
Toast.makeText(this, "Enter Pill Name to Remove", Toast.LENGTH_SHORT).show()
}
}
}

private fun setAlarm(hour: Int, minute: Int) {


val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT)

val calendar = Calendar.getInstance().apply {


set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
}

if (calendar.timeInMillis < System.currentTimeMillis()) {


calendar.add(Calendar.DAY_OF_YEAR, 1) // If time is past, schedule for next day
}

alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis,
pendingIntent)
}

private fun cancelAlarm() {


val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT)

alarmManager.cancel(pendingIntent)
}
}

package com.ankit.dosecare

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import com.ankit.dosecare.database.Pill
import java.util.*

object AlarmHelper {
fun setAlarm(context: Context, pill: Pill) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, AlarmReceiver::class.java).apply {
putExtra("PILL_NAME", pill.name)
}

val pendingIntent = PendingIntent.getBroadcast(


context, pill.id, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

try {
val timeParts = pill.time.split(":")
if (timeParts.size != 2) {
Log.e("AlarmHelper", " Invalid time format: ${pill.time}")
return
}

val hour = timeParts[0].toIntOrNull()


val minute = timeParts[1].toIntOrNull()

if (hour == null || minute == null || hour !in 0..23 || minute !in 0..59) {
Log.e("AlarmHelper", " Invalid time values: $hour:$minute")
return
}

val calendar = Calendar.getInstance().apply {


set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)

// Ensure alarm is in the future


if (before(Calendar.getInstance())) {
add(Calendar.DATE, 1) // Set for tomorrow if time has passed
}
}

Log.d("AlarmHelper", " Alarm set for: ${calendar.time}")

// Best for Doze mode (Allows alarms in idle state)


alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)

// Use `setAlarmClock()` for better accuracy on newer devices


alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(calendar.timeInMillis, pendingIntent),
pendingIntent
)

} catch (e: Exception) {


Log.e("AlarmHelper", " Error setting alarm: ${e.message}", e)
}
}
}

package com.ankit.dosecare

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.os.PowerManager
import android.widget.Toast

class AlarmReceiver : BroadcastReceiver() {


override fun onReceive(context: Context?, intent: Intent?) {
if (context == null) return

Toast.makeText(context, " Alarm Ringing!", Toast.LENGTH_LONG).show()

// Wake up the device if it's sleeping


val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"DoseCare:WakeLock"
)
wakeLock.acquire(60 * 1000L) // Keep awake for 1 minute

// Play Alarm Sound


val alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
val mediaPlayer = MediaPlayer.create(context, alarmUri)
mediaPlayer?.start()

wakeLock.release() // Release WakeLock after execution


}
}

package com.ankit.dosecare

import android.Manifest
import android.app.AlarmManager
import android.content.pm.PackageManager
import android.os.Build
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.ankit.dosecare.database.PillDatabase
import com.ankit.dosecare.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding


private lateinit var adapter: PillAdapter
private lateinit var database: PillDatabase
private val PERMISSION_REQUEST_CODE = 1001

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

database = PillDatabase.getDatabase(this)

adapter = PillAdapter(database.pillDao().getAllPills()) { pill -> }

binding.rvPillList.layoutManager = LinearLayoutManager(this)
binding.rvPillList.adapter = adapter

binding.fabAdd.setOnClickListener {
startActivity(Intent(this, AddReminderActivity::class.java))
}

binding.fabCalendar.setOnClickListener {
startActivity(Intent(this, ScheduleActivity::class.java))
}

checkAndRequestPermissions()
}

private fun checkAndRequestPermissions() {


val permissions = mutableListOf<String>()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {


val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
if (!alarmManager.canScheduleExactAlarms()) {
startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
}
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {


if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
}
}

if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_BOOT_COMPLETED)
!= PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.RECEIVE_BOOT_COMPLETED)
}

if (permissions.isNotEmpty()) {
ActivityCompat.requestPermissions(this, permissions.toTypedArray(),
PERMISSION_REQUEST_CODE)
}
}

override fun onRequestPermissionsResult(


requestCode: Int, permissions: Array<String>, grantResults: IntArray
){
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST_CODE) {
for (i in permissions.indices) {
val status = if (grantResults[i] == PackageManager.PERMISSION_GRANTED) "granted" else
"denied"
Toast.makeText(this, "${permissions[i]} $status", Toast.LENGTH_SHORT).show()
}
}
}
}

package com.ankit.dosecare.database

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "pills")
data class Pill(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String,
val dosage: String,
val time: String
)

package com.ankit.dosecare

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.ankit.dosecare.database.Pill

class PillActivity : AppCompatActivity() {


private lateinit var recyclerView: RecyclerView
private lateinit var adapter: PillAdapter
private val pillList = mutableListOf<Pill>()

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pill)

recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)

pillList.add(Pill(1, "Paracetamol", "500mg", "8:00 AM"))


pillList.add(Pill(2, "Ibuprofen", "200mg", "2:00 PM"))

adapter = PillAdapter(pillList) { pill ->


Toast.makeText(this, "Clicked: ${pill}", Toast.LENGTH_SHORT).show()
}

recyclerView.adapter = adapter
}
}

package com.ankit.dosecare

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.ankit.dosecare.database.Pill

class PillAdapter(private val pillList: List<Pill>, private val onClick: (Pill) -> Unit) :
RecyclerView.Adapter<PillAdapter.PillViewHolder>() {

class PillViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {


val pillName: TextView = itemView.findViewById(R.id.pillName)
val pillDosage: TextView = itemView.findViewById(R.id.pillDosage)
val pillTime: TextView = itemView.findViewById(R.id.pillTime)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PillViewHolder {


val view = LayoutInflater.from(parent.context).inflate(R.layout.item_pill, parent, false)
return PillViewHolder(view)
}
override fun onBindViewHolder(holder: PillViewHolder, position: Int) {
val pill = pillList[position]
holder.pillName.text = pill.name
holder.pillDosage.text = pill.dosage
holder.pillTime.text = pill.time

holder.itemView.setOnClickListener { onClick(pill) }
}

override fun getItemCount() = pillList.size


}

package com.ankit.dosecare.database

import androidx.room.*

@Dao
interface PillDao {
@Query("SELECT * FROM pills")
fun getAllPills(): List<Pill>

@Query("SELECT * FROM pills WHERE name = :pillName LIMIT 1")


fun getPillByName(pillName: String): Pill?

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPill(pill: Pill)

@Delete
fun deletePill(pill: Pill)
}

package com.ankit.dosecare.database

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [Pill::class], version = 1)


abstract class PillDatabase : RoomDatabase() {
abstract fun pillDao(): PillDao

companion object {
@Volatile
private var INSTANCE: PillDatabase? = null

fun getDatabase(context: Context): PillDatabase {


return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
PillDatabase::class.java,
"pill_database"
).allowMainThreadQueries().build()
INSTANCE = instance
instance
}
}
}
}

package com.ankit.dosecare

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.ankit.dosecare.database.PillDatabase
import com.ankit.dosecare.databinding.ActivityScheduleBinding

class ScheduleActivity : AppCompatActivity() {

private lateinit var binding: ActivityScheduleBinding


private lateinit var adapter: PillAdapter
private lateinit var database: PillDatabase

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
binding = ActivityScheduleBinding.inflate(layoutInflater)
setContentView(binding.root)

database = PillDatabase.getDatabase(this)

adapter = PillAdapter(database.pillDao().getAllPills()) { pill ->

binding.rvScheduleList.layoutManager = LinearLayoutManager(this)
binding.rvScheduleList.adapter = adapter
}
}

<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp">

<!-- Pill Name Input -->


<EditText
android:id="@+id/etPillName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Pill Name"
android:textSize="16sp"
android:padding="12dp"
android:background="@android:drawable/editbox_background"
android:layout_marginBottom="12dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<!-- Select Time Label -->


<TextView
android:id="@+id/tvTimeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reminder Time"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/etPillName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<!-- Selected Time Display -->


<EditText
android:id="@+id/etPillTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="No Time Selected"
android:textSize="16sp"
android:padding="12dp"
android:background="@android:drawable/editbox_background"
android:focusable="false"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/tvTimeLabel"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<!-- Pick Time Button -->


<Button
android:id="@+id/btnPickTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pick Time"
android:textSize="16sp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@id/etPillTime"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<!-- Save Reminder Button -->


<Button
android:id="@+id/btnSaveReminder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save Reminder"
android:textSize="16sp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/btnPickTime"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<!-- Remove Reminder Button -->


<Button
android:id="@+id/btnRemoveReminder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remove Reminder"
android:textSize="16sp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@id/btnSaveReminder"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

<?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">

<TextView
android:id="@+id/tvWelcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Welcome to DoseCare!"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="32dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvPillList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="16dp"
app:layout_constraintTop_toBottomOf="@id/tvWelcome"
app:layout_constraintBottom_toTopOf="@id/fabAdd"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabCalendar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_calendar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="16dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<?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">

<CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvScheduleList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="16dp"
app:layout_constraintTop_toBottomOf="@id/calendarView"
app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">

<TextView
android:id="@+id/pillName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pill Name"
android:textSize="18sp" />

<TextView
android:id="@+id/pillDosage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dosage"
android:textSize="16sp" />

<TextView
android:id="@+id/pillTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Time"
android:textSize="16sp" />

</LinearLayout>

You might also like