Preserve event-local timestamp timezone
This commit is contained in:
@@ -77,7 +77,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
|||||||
entries.forEach { entry ->
|
entries.forEach { entry ->
|
||||||
view.logRows.addView(TextView(requireContext()).apply {
|
view.logRows.addView(TextView(requireContext()).apply {
|
||||||
text = settings.order.filter { it in settings.visibleFields }.mapNotNull { field -> when (field) {
|
text = settings.order.filter { it in settings.visibleFields }.mapNotNull { field -> when (field) {
|
||||||
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone)
|
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone, entry.eventTimeZoneId)
|
||||||
LogField.APP_NAME -> entry.appName
|
LogField.APP_NAME -> entry.appName
|
||||||
LogField.PACKAGE_NAME -> entry.packageName
|
LogField.PACKAGE_NAME -> entry.packageName
|
||||||
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
||||||
@@ -95,9 +95,13 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun timestamp(value: Long, zone: TimestampZone): String {
|
private fun timestamp(value: Long, zone: TimestampZone, eventTimeZoneId: String?): String {
|
||||||
val format = DateFormat.getDateTimeInstance()
|
val format = DateFormat.getDateTimeInstance()
|
||||||
if (zone == TimestampZone.UTC) format.timeZone = java.util.TimeZone.getTimeZone("UTC")
|
format.timeZone = when (zone) {
|
||||||
|
TimestampZone.UTC -> java.util.TimeZone.getTimeZone("UTC")
|
||||||
|
TimestampZone.LOCAL_NOW -> java.util.TimeZone.getDefault()
|
||||||
|
TimestampZone.EVENT_LOCAL -> eventTimeZoneId?.let(java.util.TimeZone::getTimeZone) ?: java.util.TimeZone.getDefault()
|
||||||
|
}
|
||||||
return format.format(Date(value))
|
return format.format(Date(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class NotificationCaptureService : NotificationListenerService() {
|
|||||||
NotificationRuleEvaluator.allows(ruleStore.ruleFor(LoggingType.IMAGE_CONTENT), snapshot.packageName)
|
NotificationRuleEvaluator.allows(ruleStore.ruleFor(LoggingType.IMAGE_CONTENT), snapshot.packageName)
|
||||||
val entry = NotificationLogEntry(
|
val entry = NotificationLogEntry(
|
||||||
recordedAtEpochMillis = System.currentTimeMillis(),
|
recordedAtEpochMillis = System.currentTimeMillis(),
|
||||||
|
eventTimeZoneId = java.util.TimeZone.getDefault().id,
|
||||||
packageName = snapshot.packageName,
|
packageName = snapshot.packageName,
|
||||||
appName = appName,
|
appName = appName,
|
||||||
action = action,
|
action = action,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ object NotificationLogEntryJson {
|
|||||||
JSONObject()
|
JSONObject()
|
||||||
.put("id", entry.id)
|
.put("id", entry.id)
|
||||||
.put("recordedAtEpochMillis", entry.recordedAtEpochMillis)
|
.put("recordedAtEpochMillis", entry.recordedAtEpochMillis)
|
||||||
|
.put("eventTimeZoneId", entry.eventTimeZoneId)
|
||||||
.put("packageName", entry.packageName)
|
.put("packageName", entry.packageName)
|
||||||
.put("appName", entry.appName)
|
.put("appName", entry.appName)
|
||||||
.put("action", entry.action.name)
|
.put("action", entry.action.name)
|
||||||
@@ -29,6 +30,7 @@ object NotificationLogEntryJson {
|
|||||||
NotificationLogEntry(
|
NotificationLogEntry(
|
||||||
id = entry.getString("id"),
|
id = entry.getString("id"),
|
||||||
recordedAtEpochMillis = entry.getLong("recordedAtEpochMillis"),
|
recordedAtEpochMillis = entry.getLong("recordedAtEpochMillis"),
|
||||||
|
eventTimeZoneId = entry.optString("eventTimeZoneId").takeIf { it.isNotEmpty() },
|
||||||
packageName = entry.getString("packageName"),
|
packageName = entry.getString("packageName"),
|
||||||
appName = entry.getString("appName"),
|
appName = entry.getString("appName"),
|
||||||
action = NotificationAction.valueOf(entry.getString("action")),
|
action = NotificationAction.valueOf(entry.getString("action")),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ object LogExporter {
|
|||||||
settings.order.filter { it in settings.visibleFields }.map(::header),
|
settings.order.filter { it in settings.visibleFields }.map(::header),
|
||||||
) + entries.sortedByDescending { it.recordedAtEpochMillis }.map { entry ->
|
) + entries.sortedByDescending { it.recordedAtEpochMillis }.map { entry ->
|
||||||
settings.order.filter { it in settings.visibleFields }.map { field -> when (field) {
|
settings.order.filter { it in settings.visibleFields }.map { field -> when (field) {
|
||||||
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone)
|
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone, entry.eventTimeZoneId)
|
||||||
LogField.APP_NAME -> entry.appName; LogField.PACKAGE_NAME -> entry.packageName
|
LogField.APP_NAME -> entry.appName; LogField.PACKAGE_NAME -> entry.packageName
|
||||||
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
||||||
LogField.CONTENTS -> entry.contents ?: ""
|
LogField.CONTENTS -> entry.contents ?: ""
|
||||||
@@ -49,7 +49,7 @@ object LogExporter {
|
|||||||
private fun header(field: LogField) = field.name.lowercase().replace('_', ' ')
|
private fun header(field: LogField) = field.name.lowercase().replace('_', ' ')
|
||||||
private fun htmlValue(field: LogField, entry: NotificationLogEntry, settings: LogViewSettings, imagePath: String?): String {
|
private fun htmlValue(field: LogField, entry: NotificationLogEntry, settings: LogViewSettings, imagePath: String?): String {
|
||||||
val value = when (field) {
|
val value = when (field) {
|
||||||
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone)
|
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone, entry.eventTimeZoneId)
|
||||||
LogField.APP_NAME -> entry.appName
|
LogField.APP_NAME -> entry.appName
|
||||||
LogField.PACKAGE_NAME -> entry.packageName
|
LogField.PACKAGE_NAME -> entry.packageName
|
||||||
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
||||||
@@ -62,7 +62,13 @@ object LogExporter {
|
|||||||
escaped
|
escaped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun timestamp(value: Long, zone: TimestampZone): String = DateFormat.getDateTimeInstance().apply { if (zone == TimestampZone.UTC) timeZone = TimeZone.getTimeZone("UTC") }.format(Date(value))
|
private fun timestamp(value: Long, zone: TimestampZone, eventTimeZoneId: String?): String = DateFormat.getDateTimeInstance().apply {
|
||||||
|
timeZone = when (zone) {
|
||||||
|
TimestampZone.UTC -> TimeZone.getTimeZone("UTC")
|
||||||
|
TimestampZone.LOCAL_NOW -> TimeZone.getDefault()
|
||||||
|
TimestampZone.EVENT_LOCAL -> eventTimeZoneId?.let(TimeZone::getTimeZone) ?: TimeZone.getDefault()
|
||||||
|
}
|
||||||
|
}.format(Date(value))
|
||||||
private fun csvValue(value: String) = "\"${value.replace("\"", "\"\"")}\""
|
private fun csvValue(value: String) = "\"${value.replace("\"", "\"\"")}\""
|
||||||
private fun escape(value: String) = value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
|
private fun escape(value: String) = value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.util.UUID
|
|||||||
data class NotificationLogEntry(
|
data class NotificationLogEntry(
|
||||||
val id: String = UUID.randomUUID().toString(),
|
val id: String = UUID.randomUUID().toString(),
|
||||||
val recordedAtEpochMillis: Long,
|
val recordedAtEpochMillis: Long,
|
||||||
|
/** The device timezone at capture time, retained for event-local display/export. */
|
||||||
|
val eventTimeZoneId: String? = null,
|
||||||
val packageName: String,
|
val packageName: String,
|
||||||
val appName: String,
|
val appName: String,
|
||||||
val action: NotificationAction,
|
val action: NotificationAction,
|
||||||
|
|||||||
Reference in New Issue
Block a user