Skip to content

Commit d45dbd5

Browse files
authored
Merge pull request #190 from akaMrNagar/dev
Bug and crash fixes on native side along with UI improvements
2 parents fd794c6 + c321105 commit d45dbd5

File tree

73 files changed

+1449
-855
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1449
-855
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,4 @@ A huge thank you to our amazing localization contributors in making Mindful acce
123123
[*@fireflurry*](https://crowdin.com/profile/fireflurry),
124124
[*@youquan0914*](https://crowdin.com/profile/youquan0914),
125125
[*@e_cllf*](https://crowdin.com/profile/e_cllf).
126+
[*@cypherzane*](https://crowdin.com/profile/cypherzane).

android/app/src/main/java/com/mindful/android/helpers/device/PermissionsHelper.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ import android.util.Log
3131
import android.widget.Toast
3232
import androidx.core.app.ActivityCompat
3333
import androidx.core.app.NotificationManagerCompat
34+
import androidx.core.net.toUri
35+
import com.mindful.android.AppConstants
3436
import com.mindful.android.R
3537
import com.mindful.android.helpers.storage.SharedPrefsHelper
3638
import com.mindful.android.receivers.DeviceAdminReceiver
3739
import com.mindful.android.services.accessibility.MindfulAccessibilityService
38-
import com.mindful.android.AppConstants
3940
import com.mindful.android.utils.Utils
4041

4142
/**
@@ -116,7 +117,7 @@ object PermissionsHelper {
116117
if (askPermissionToo) {
117118
try {
118119
val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
119-
.setData(Uri.parse("package:${context.packageName}"))
120+
.setData("package:${context.packageName}".toUri())
120121

121122
context.startActivity(intent)
122123
} catch (e: ActivityNotFoundException) {

android/app/src/main/java/com/mindful/android/helpers/storage/DriftDbHelper.kt

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,94 +4,86 @@ import android.content.ContentValues
44
import android.content.Context
55
import android.database.sqlite.SQLiteDatabase
66
import android.util.Log
7+
import androidx.core.database.sqlite.transaction
78
import com.mindful.android.models.Notification
89
import java.io.File
910

10-
open class DriftDbHelper(context: Context) {
11-
companion object {
12-
private const val TAG = "Mindful.DriftDbHelper"
13-
}
14-
15-
private var db: SQLiteDatabase? = null
1611

17-
init {
18-
openDatabase(context)
19-
}
12+
object DriftDbHelper {
13+
private const val TAG = "Mindful.DriftDbHelper"
2014

2115
// Open the database if it's not already open
22-
private fun openDatabase(context: Context) {
23-
if (db == null) {
16+
private fun openDatabase(context: Context): SQLiteDatabase? {
17+
try {
2418
// /data/user/0/com.mindful.android/app_flutter/Mindful0.sqlite
2519
val dbPath = "${context.dataDir.path}/app_flutter/Mindful.sqlite"
2620
val dbFile = File(dbPath)
2721

2822
/// Will open only if it exists
2923
if (dbFile.exists()) {
30-
db = SQLiteDatabase.openOrCreateDatabase(dbFile, null)
31-
Log.d("Mindful.DriftDbHelper", "openDatabase: Database opened successfully")
24+
val db = SQLiteDatabase.openDatabase(
25+
dbFile.path,
26+
null,
27+
SQLiteDatabase.OPEN_READWRITE,
28+
)
29+
Log.d(TAG, "openDatabase: Database opened successfully")
30+
return db
3231
}
33-
}
34-
35-
}
3632

37-
// Get the database instance
38-
fun getDatabase(): SQLiteDatabase {
39-
return db
40-
?: throw IllegalStateException("Database not initialized. Call AppDbHelper.openDb(context) first.")
33+
return null
34+
} catch (e: Exception) {
35+
Log.e(TAG, "openDatabase(): Failed to open database", e)
36+
SharedPrefsHelper.insertCrashLogToPrefs(context, e)
37+
return null
38+
}
4139
}
4240

43-
// Close the database
44-
private fun closeDatabase() {
45-
db?.close()
46-
db = null
47-
48-
}
4941

5042
// ================================ DAO API ==========================================
5143

5244
// Insert multiple notifications using a transaction
45+
@Synchronized
5346
fun insertNotifications(
47+
context: Context,
5448
notifications: List<Notification>,
55-
autoCloseDb: Boolean = true,
5649
): Boolean {
50+
val db = openDatabase(context)
51+
5752
try {
5853
// Begin the transaction
59-
db?.beginTransaction()
60-
61-
val values = ContentValues()
62-
for (notification in notifications) {
63-
// Clear values for the next insert
64-
values.clear()
65-
values.put("key", notification.key)
66-
values.put("package_name", notification.packageName)
67-
values.put("title", notification.title)
68-
values.put("content", notification.content)
69-
// Convert MsEpoch to SecEpoch
70-
values.put("time_stamp", notification.timeStamp / 1000L)
71-
values.put("category", notification.category)
72-
values.put("is_read", notification.isRead)
73-
74-
// Insert the notification into the database
75-
db?.insert("notifications_table", null, values)
54+
db?.transaction {
55+
val values = ContentValues()
56+
for (notification in notifications) {
57+
// Clear values for the next insert
58+
values.clear()
59+
values.put("key", notification.key)
60+
values.put("package_name", notification.packageName)
61+
values.put("title", notification.title)
62+
values.put("content", notification.content)
63+
// Convert MsEpoch to SecEpoch
64+
values.put("time_stamp", notification.timeStamp / 1000L)
65+
values.put("category", notification.category)
66+
values.put("is_read", notification.isRead)
67+
68+
// Insert the notification into the database
69+
this.insert("notifications_table", null, values)
70+
}
7671
}
77-
78-
// End transaction and Close db if needed
79-
db?.setTransactionSuccessful()
80-
db?.endTransaction()
81-
8272
Log.d(TAG, "insertNotifications: Successfully inserted notifications")
8373
return true
8474
} catch (e: Exception) {
8575
Log.e(TAG, "insertNotifications: Failed to insert notifications", e)
8676
return false
8777
} finally {
88-
if (autoCloseDb) closeDatabase()
78+
db?.close()
8979
}
9080
}
9181

82+
@Synchronized
9283
fun fetchLast24HourUnreadNotifications(
93-
autoCloseDb: Boolean = true,
84+
context: Context,
9485
): List<Notification> {
86+
val db = openDatabase(context)
9587
val result = mutableListOf<Notification>()
9688
val last24HoursSec = System.currentTimeMillis() / 1000L - 24 * 60 * 60
9789

@@ -118,38 +110,38 @@ open class DriftDbHelper(context: Context) {
118110
} catch (e: Exception) {
119111
Log.e(TAG, "fetchLast24HourUnreadNotifications: Error fetching notifications", e)
120112
} finally {
121-
if (autoCloseDb) closeDatabase()
113+
db?.close()
122114
}
123115

124116
return result
125117
}
126118

119+
@Synchronized
127120
fun markNotificationsAsRead(
121+
context: Context,
128122
ids: List<Int>,
129-
autoCloseDb: Boolean = true,
130123
) {
131124
if (ids.isEmpty()) return
125+
val db = openDatabase(context)
126+
132127

133128
try {
134-
db?.beginTransaction()
135-
val values = ContentValues().apply { put("is_read", 1) }
136-
ids.forEach { id ->
137-
db?.update(
138-
"notifications_table",
139-
values,
140-
"id = ?",
141-
arrayOf(id.toString())
142-
)
129+
db?.transaction {
130+
val values = ContentValues().apply { put("is_read", 1) }
131+
ids.forEach { id ->
132+
this.update(
133+
"notifications_table",
134+
values,
135+
"id = ?",
136+
arrayOf(id.toString())
137+
)
138+
}
143139
}
144-
145-
// End transaction and Close db if needed
146-
db?.setTransactionSuccessful()
147-
db?.endTransaction()
148140
Log.d(TAG, "markNotificationsAsRead: Marked ${ids.size} notifications as read")
149141
} catch (e: Exception) {
150142
Log.e(TAG, "markNotificationsAsRead: Error marking notifications as read", e)
151143
} finally {
152-
if (autoCloseDb) closeDatabase()
144+
db?.close()
153145
}
154146
}
155147

android/app/src/main/java/com/mindful/android/helpers/usages/NetworkUsageHelper.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,31 @@ object NetworkUsageHelper {
9999
end: Long,
100100
): Map<Int, Long> {
101101
val usageMap = mutableMapOf<Int, Long>()
102-
val networkStats = networkStatsManager.querySummary(networkType, null, start, end)
103-
104102
try {
105-
val bucket = NetworkStats.Bucket()
103+
val networkStats = networkStatsManager.querySummary(networkType, null, start, end)
106104

107-
while (networkStats.hasNextBucket()) {
108-
networkStats.getNextBucket(bucket)
109-
val uid = bucket.uid
110-
usageMap[uid] =
111-
usageMap.getOrDefault(uid, 0L) + (bucket.rxBytes + bucket.txBytes)
112-
}
105+
networkStats.use {
106+
val bucket = NetworkStats.Bucket()
113107

108+
while (networkStats.hasNextBucket()) {
109+
networkStats.getNextBucket(bucket)
110+
val uid = bucket.uid
111+
usageMap[uid] =
112+
usageMap.getOrDefault(uid, 0L) + (bucket.rxBytes + bucket.txBytes)
113+
}
114+
115+
}
114116
} catch (e: Exception) {
115117
Log.e(
116118
TAG,
117119
"fetchNetworkUsageForInterval: Error fetching network usage for type $networkType",
118120
e
119121
)
120-
} finally {
121-
networkStats.close()
122122
}
123123

124124
return usageMap
125125
.mapValues { it.value / 1024 } // Convert bytes to KBs
126-
.filterValues { it > 0L } // Remove entries with no usage
126+
.filterValues { it > 0L } // Only keep entries with usage
127127
}
128128

129129

android/app/src/main/java/com/mindful/android/helpers/usages/ScreenUsageHelper.kt

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,37 +37,38 @@ object ScreenUsageHelper {
3737
): Map<String, Long> {
3838
val usageMap = mutableMapOf<String, Long>()
3939
val lastResumedEvents = mutableMapOf<String, UsageEvents.Event>()
40+
runCatching {
41+
// Load 3 hour earlier events for granularity
42+
val usageEvents = usageStatsManager.queryEvents(start - (3 * 60 * 60 * 1000), end)
4043

41-
// Load 3 hour earlier events for granularity
42-
val usageEvents = usageStatsManager.queryEvents(start - (3 * 60 * 60 * 1000), end)
44+
while (usageEvents.hasNextEvent()) {
45+
// Never move this outside the while loop otherwise the usage will be 0
46+
val event = UsageEvents.Event()
47+
usageEvents.getNextEvent(event)
4348

44-
while (usageEvents.hasNextEvent()) {
45-
// Never move this outside the while loop otherwise the usage will be 0
46-
val event = UsageEvents.Event()
47-
usageEvents.getNextEvent(event)
48-
49-
val packageName = event.packageName
50-
val currentTimeStamp = event.timeStamp
51-
val eventKey = packageName + event.className
49+
val packageName = event.packageName
50+
val currentTimeStamp = event.timeStamp
51+
val eventKey = packageName + event.className
5252

53-
when (event.eventType) {
54-
UsageEvents.Event.ACTIVITY_RESUMED -> lastResumedEvents[eventKey] = event
55-
UsageEvents.Event.ACTIVITY_PAUSED, UsageEvents.Event.ACTIVITY_STOPPED -> {
56-
// If any resume event for the key
57-
lastResumedEvents.remove(eventKey)?.let { lastResumedEvent ->
58-
/// If app is paused or stopped after the start
59-
if (currentTimeStamp > start) {
60-
// MaxOf guarantee that the resume event is after the start
61-
val resumeTimeStamp = maxOf(lastResumedEvent.timeStamp, start)
62-
usageMap[packageName] = usageMap.getOrDefault(
63-
packageName,
64-
0L
65-
) + (currentTimeStamp - resumeTimeStamp)
53+
when (event.eventType) {
54+
UsageEvents.Event.ACTIVITY_RESUMED -> lastResumedEvents[eventKey] = event
55+
UsageEvents.Event.ACTIVITY_PAUSED, UsageEvents.Event.ACTIVITY_STOPPED -> {
56+
// If any resume event for the key
57+
lastResumedEvents.remove(eventKey)?.let { lastResumedEvent ->
58+
/// If app is paused or stopped after the start
59+
if (currentTimeStamp > start) {
60+
// MaxOf guarantee that the resume event is after the start
61+
val resumeTimeStamp = maxOf(lastResumedEvent.timeStamp, start)
62+
usageMap[packageName] = usageMap.getOrDefault(
63+
packageName,
64+
0L
65+
) + (currentTimeStamp - resumeTimeStamp)
66+
}
6667
}
6768
}
68-
}
6969

70-
else -> {}
70+
else -> {}
71+
}
7172
}
7273
}
7374

@@ -82,7 +83,7 @@ object ScreenUsageHelper {
8283

8384
return usageMap
8485
.mapValues { it.value / 1000 } // Convert ms to seconds
85-
.filterValues { it > 0L } // Remove entries with no usage
86+
.filterValues { it > 0L } // Only keep entries with usage
8687
}
8788

8889
/**

android/app/src/main/java/com/mindful/android/receivers/DeviceLockUnlockReceiver.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ import android.content.Context
1616
import android.content.Intent
1717
import android.content.IntentFilter
1818
import android.util.Log
19-
import androidx.annotation.MainThread
19+
import androidx.annotation.WorkerThread
2020
import com.mindful.android.helpers.storage.SharedPrefsHelper
2121
import com.mindful.android.utils.Utils
2222

2323
/**
2424
* BroadcastReceiver that monitors device lock/unlock events and tracks app launches while the device is unlocked.
2525
*/
2626
class DeviceLockUnlockReceiver(
27-
@MainThread
27+
@WorkerThread
2828
private val onDeviceLockChanged: (isUnLocked: Boolean) -> Unit,
2929
) : BroadcastReceiver() {
3030
companion object {
@@ -59,16 +59,18 @@ class DeviceLockUnlockReceiver(
5959

6060

6161
override fun onReceive(context: Context, intent: Intent) {
62-
when (intent.action) {
63-
Intent.ACTION_USER_PRESENT -> {
64-
Log.d(TAG, "onReceive: User UNLOCKED the device and device is ACTIVE")
65-
onDeviceLockChanged.invoke(true)
66-
}
62+
Thread {
63+
when (intent.action) {
64+
Intent.ACTION_USER_PRESENT -> {
65+
Log.d(TAG, "onReceive: User UNLOCKED the device and device is ACTIVE")
66+
onDeviceLockChanged.invoke(true)
67+
}
6768

68-
Intent.ACTION_SCREEN_OFF -> {
69-
Log.d(TAG, "onReceive: User LOCKED the device and device is INACTIVE")
70-
onDeviceLockChanged.invoke(false)
69+
Intent.ACTION_SCREEN_OFF -> {
70+
Log.d(TAG, "onReceive: User LOCKED the device and device is INACTIVE")
71+
onDeviceLockChanged.invoke(false)
72+
}
7173
}
72-
}
74+
}.start()
7375
}
7476
}

0 commit comments

Comments
 (0)