1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.launcher3.util 18 19 import java.io.PrintWriter 20 import java.text.SimpleDateFormat 21 import java.util.Date 22 import java.util.Locale 23 24 /** 25 * A utility class to record and log events. Events are stored in a fixed size array and old logs 26 * are purged as new events come. 27 */ 28 class EventLogArray(private val name: String, size: Int) { 29 30 companion object { 31 private const val TYPE_ONE_OFF = 0 32 private const val TYPE_FLOAT = 1 33 private const val TYPE_INTEGER = 2 34 private const val TYPE_BOOL_TRUE = 3 35 private const val TYPE_BOOL_FALSE = 4 isEntrySamenull36 private fun isEntrySame(entry: EventEntry?, type: Int, event: String): Boolean { 37 return entry != null && entry.type == type && entry.event == event 38 } 39 } 40 41 private val logs: Array<EventEntry?> 42 private var nextIndex = 0 43 44 init { 45 logs = arrayOfNulls(size) 46 } 47 addLognull48 fun addLog(event: String) { 49 addLog(TYPE_ONE_OFF, event, 0f) 50 } 51 addLognull52 fun addLog(event: String, extras: Int) { 53 addLog(TYPE_INTEGER, event, extras.toFloat()) 54 } 55 addLognull56 fun addLog(event: String, extras: Float) { 57 addLog(TYPE_FLOAT, event, extras) 58 } 59 addLognull60 fun addLog(event: String, extras: Boolean) { 61 addLog(if (extras) TYPE_BOOL_TRUE else TYPE_BOOL_FALSE, event, 0f) 62 } 63 addLognull64 private fun addLog(type: Int, event: String, extras: Float) { 65 // Merge the logs if it's a duplicate 66 val last = (nextIndex + logs.size - 1) % logs.size 67 val secondLast = (nextIndex + logs.size - 2) % logs.size 68 if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) { 69 logs[last]!!.update(type, event, extras) 70 logs[secondLast]!!.duplicateCount++ 71 return 72 } 73 if (logs[nextIndex] == null) { 74 logs[nextIndex] = EventEntry() 75 } 76 logs[nextIndex]!!.update(type, event, extras) 77 nextIndex = (nextIndex + 1) % logs.size 78 } 79 dumpnull80 fun dump(prefix: String, writer: PrintWriter) { 81 writer.println("$prefix$name event history:") 82 val sdf = SimpleDateFormat(" HH:mm:ss.SSSZ ", Locale.US) 83 val date = Date() 84 for (i in logs.indices) { 85 val log = logs[(nextIndex + logs.size - i - 1) % logs.size] ?: continue 86 date.time = log.time 87 val msg = StringBuilder(prefix).append(sdf.format(date)).append(log.event) 88 when (log.type) { 89 TYPE_BOOL_FALSE -> msg.append(": false") 90 TYPE_BOOL_TRUE -> msg.append(": true") 91 TYPE_FLOAT -> msg.append(": ").append(log.extras) 92 TYPE_INTEGER -> msg.append(": ").append(log.extras.toInt()) 93 else -> {} 94 } 95 if (log.duplicateCount > 0) { 96 msg.append(" & ").append(log.duplicateCount).append(" similar events") 97 } 98 writer.println(msg) 99 } 100 } 101 102 /** A single event entry. */ 103 private class EventEntry { 104 var type = 0 105 var event: String? = null 106 var extras = 0f 107 var time: Long = 0 108 var duplicateCount = 0 updatenull109 fun update(type: Int, event: String, extras: Float) { 110 this.type = type 111 this.event = event 112 this.extras = extras 113 time = System.currentTimeMillis() 114 duplicateCount = 0 115 } 116 } 117 } 118