1 /* 2 * Copyright (C) 2022 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.systemui.log.table 18 19 import androidx.annotation.VisibleForTesting 20 21 /** 22 * A object used with [TableLogBuffer] to store changes in variables over time. Is recyclable. 23 * 24 * Each message represents a change to exactly 1 type, specified by [DataType]. 25 * 26 * @property isInitial see [TableLogBuffer.logChange(String, Boolean, (TableRowLogger) -> Unit]. 27 */ 28 data class TableChange( 29 var timestamp: Long = 0, 30 private var columnPrefix: String = "", 31 private var columnName: String = "", 32 private var isInitial: Boolean = false, 33 private var type: DataType = DataType.EMPTY, 34 private var bool: Boolean = false, 35 private var int: Int? = null, 36 private var str: String? = null, 37 ) { 38 init { 39 // Truncate any strings that were passed into the constructor. [reset] and [set] will take 40 // care of the rest of the truncation. 41 this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH) 42 this.columnName = columnName.take(MAX_STRING_LENGTH) 43 this.str = str?.take(MAX_STRING_LENGTH) 44 } 45 46 /** Resets to default values so that the object can be recycled. */ 47 fun reset(timestamp: Long, columnPrefix: String, columnName: String, isInitial: Boolean) { 48 this.timestamp = timestamp 49 this.columnPrefix = columnPrefix.take(MAX_STRING_LENGTH) 50 this.columnName = columnName.take(MAX_STRING_LENGTH) 51 this.isInitial = isInitial 52 this.type = DataType.EMPTY 53 this.bool = false 54 this.int = 0 55 this.str = null 56 } 57 58 /** Sets this to store a string change. */ 59 fun set(value: String?) { 60 type = DataType.STRING 61 str = value?.take(MAX_STRING_LENGTH) 62 } 63 64 /** Sets this to store a boolean change. */ 65 fun set(value: Boolean) { 66 type = DataType.BOOLEAN 67 bool = value 68 } 69 70 /** Sets this to store an int change. */ 71 fun set(value: Int?) { 72 type = DataType.INT 73 int = value 74 } 75 76 /** Updates this to store the same value as [change]. */ 77 fun updateTo(change: TableChange) { 78 reset(change.timestamp, change.columnPrefix, change.columnName, change.isInitial) 79 when (change.type) { 80 DataType.STRING -> set(change.str) 81 DataType.INT -> set(change.int) 82 DataType.BOOLEAN -> set(change.bool) 83 DataType.EMPTY -> {} 84 } 85 } 86 87 /** Returns true if this object has a change. */ 88 fun hasData(): Boolean { 89 return columnName.isNotBlank() && type != DataType.EMPTY 90 } 91 92 fun getName(): String { 93 return if (columnPrefix.isNotBlank()) { 94 "$columnPrefix.$columnName" 95 } else { 96 columnName 97 } 98 } 99 100 fun getColumnName() = columnName 101 102 fun getVal(): String { 103 val value = 104 when (type) { 105 DataType.EMPTY -> null 106 DataType.STRING -> str 107 DataType.INT -> int 108 DataType.BOOLEAN -> bool 109 }.toString() 110 return "${if (isInitial) IS_INITIAL_PREFIX else ""}$value" 111 } 112 113 enum class DataType { 114 STRING, 115 BOOLEAN, 116 INT, 117 EMPTY, 118 } 119 120 companion object { 121 @VisibleForTesting const val IS_INITIAL_PREFIX = "**" 122 // Don't allow any strings larger than this length so that we have a hard upper limit on the 123 // size of the data stored by the buffer. 124 @VisibleForTesting const val MAX_STRING_LENGTH = 500 125 } 126 } 127