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 ->
|
||||
view.logRows.addView(TextView(requireContext()).apply {
|
||||
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.PACKAGE_NAME -> entry.packageName
|
||||
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()
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ class NotificationCaptureService : NotificationListenerService() {
|
||||
NotificationRuleEvaluator.allows(ruleStore.ruleFor(LoggingType.IMAGE_CONTENT), snapshot.packageName)
|
||||
val entry = NotificationLogEntry(
|
||||
recordedAtEpochMillis = System.currentTimeMillis(),
|
||||
eventTimeZoneId = java.util.TimeZone.getDefault().id,
|
||||
packageName = snapshot.packageName,
|
||||
appName = appName,
|
||||
action = action,
|
||||
|
||||
@@ -13,6 +13,7 @@ object NotificationLogEntryJson {
|
||||
JSONObject()
|
||||
.put("id", entry.id)
|
||||
.put("recordedAtEpochMillis", entry.recordedAtEpochMillis)
|
||||
.put("eventTimeZoneId", entry.eventTimeZoneId)
|
||||
.put("packageName", entry.packageName)
|
||||
.put("appName", entry.appName)
|
||||
.put("action", entry.action.name)
|
||||
@@ -29,6 +30,7 @@ object NotificationLogEntryJson {
|
||||
NotificationLogEntry(
|
||||
id = entry.getString("id"),
|
||||
recordedAtEpochMillis = entry.getLong("recordedAtEpochMillis"),
|
||||
eventTimeZoneId = entry.optString("eventTimeZoneId").takeIf { it.isNotEmpty() },
|
||||
packageName = entry.getString("packageName"),
|
||||
appName = entry.getString("appName"),
|
||||
action = NotificationAction.valueOf(entry.getString("action")),
|
||||
|
||||
@@ -40,7 +40,7 @@ object LogExporter {
|
||||
settings.order.filter { it in settings.visibleFields }.map(::header),
|
||||
) + entries.sortedByDescending { it.recordedAtEpochMillis }.map { entry ->
|
||||
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.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
||||
LogField.CONTENTS -> entry.contents ?: ""
|
||||
@@ -49,7 +49,7 @@ object LogExporter {
|
||||
private fun header(field: LogField) = field.name.lowercase().replace('_', ' ')
|
||||
private fun htmlValue(field: LogField, entry: NotificationLogEntry, settings: LogViewSettings, imagePath: String?): String {
|
||||
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.PACKAGE_NAME -> entry.packageName
|
||||
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
|
||||
@@ -62,7 +62,13 @@ object LogExporter {
|
||||
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 escape(value: String) = value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import java.util.UUID
|
||||
data class NotificationLogEntry(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val recordedAtEpochMillis: Long,
|
||||
/** The device timezone at capture time, retained for event-local display/export. */
|
||||
val eventTimeZoneId: String? = null,
|
||||
val packageName: String,
|
||||
val appName: String,
|
||||
val action: NotificationAction,
|
||||
|
||||
Reference in New Issue
Block a user