| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package com.android.launcher3.util |
| |
| import java.io.PrintWriter |
| import java.text.SimpleDateFormat |
| import java.util.Date |
| import java.util.Locale |
| |
| /** |
| * A utility class to record and log events. Events are stored in a fixed size array and old logs |
| * are purged as new events come. |
| */ |
| class EventLogArray(private val name: String, size: Int) { |
| |
| companion object { |
| private const val TYPE_ONE_OFF = 0 |
| private const val TYPE_FLOAT = 1 |
| private const val TYPE_INTEGER = 2 |
| private const val TYPE_BOOL_TRUE = 3 |
| private const val TYPE_BOOL_FALSE = 4 |
| private fun isEntrySame(entry: EventEntry?, type: Int, event: String): Boolean { |
| return entry != null && entry.type == type && entry.event == event |
| } |
| } |
| |
| private val logs: Array<EventEntry?> |
| private var nextIndex = 0 |
| |
| init { |
| logs = arrayOfNulls(size) |
| } |
| |
| fun addLog(event: String) { |
| addLog(TYPE_ONE_OFF, event, 0f) |
| } |
| |
| fun addLog(event: String, extras: Int) { |
| addLog(TYPE_INTEGER, event, extras.toFloat()) |
| } |
| |
| fun addLog(event: String, extras: Float) { |
| addLog(TYPE_FLOAT, event, extras) |
| } |
| |
| fun addLog(event: String, extras: Boolean) { |
| addLog(if (extras) TYPE_BOOL_TRUE else TYPE_BOOL_FALSE, event, 0f) |
| } |
| |
| private fun addLog(type: Int, event: String, extras: Float) { |
| // Merge the logs if it's a duplicate |
| val last = (nextIndex + logs.size - 1) % logs.size |
| val secondLast = (nextIndex + logs.size - 2) % logs.size |
| if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) { |
| logs[last]!!.update(type, event, extras) |
| logs[secondLast]!!.duplicateCount++ |
| return |
| } |
| if (logs[nextIndex] == null) { |
| logs[nextIndex] = EventEntry() |
| } |
| logs[nextIndex]!!.update(type, event, extras) |
| nextIndex = (nextIndex + 1) % logs.size |
| } |
| |
| fun dump(prefix: String, writer: PrintWriter) { |
| writer.println("$prefix$name event history:") |
| val sdf = SimpleDateFormat(" HH:mm:ss.SSSZ ", Locale.US) |
| val date = Date() |
| for (i in logs.indices) { |
| val log = logs[(nextIndex + logs.size - i - 1) % logs.size] ?: continue |
| date.time = log.time |
| val msg = StringBuilder(prefix).append(sdf.format(date)).append(log.event) |
| when (log.type) { |
| TYPE_BOOL_FALSE -> msg.append(": false") |
| TYPE_BOOL_TRUE -> msg.append(": true") |
| TYPE_FLOAT -> msg.append(": ").append(log.extras) |
| TYPE_INTEGER -> msg.append(": ").append(log.extras.toInt()) |
| else -> {} |
| } |
| if (log.duplicateCount > 0) { |
| msg.append(" & ").append(log.duplicateCount).append(" similar events") |
| } |
| writer.println(msg) |
| } |
| } |
| |
| /** A single event entry. */ |
| private class EventEntry { |
| var type = 0 |
| var event: String? = null |
| var extras = 0f |
| var time: Long = 0 |
| var duplicateCount = 0 |
| fun update(type: Int, event: String, extras: Float) { |
| this.type = type |
| this.event = event |
| this.extras = extras |
| time = System.currentTimeMillis() |
| duplicateCount = 0 |
| } |
| } |
| } |