1 /* <lambda>null2 * 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.systemui.util 18 19 import com.android.app.tracing.traceSection 20 import java.util.concurrent.CopyOnWriteArrayList 21 import java.util.function.Consumer 22 23 /** 24 * A collection of listeners, observers, callbacks, etc. 25 * 26 * This container is optimized for infrequent mutation and frequent iteration, with thread safety 27 * and reentrant-safety guarantees as well. Specifically, to ensure that 28 * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes made to 29 * the set after the iterator is constructed. 30 * 31 * This class provides all the abilities of [ListenerSet], except that each listener has a name 32 * calculated at runtime which can be used for time-efficient tracing of listener invocations. 33 */ 34 class NamedListenerSet<E : Any>( 35 private val getName: (E) -> String = { it.javaClass.name }, 36 ) : IListenerSet<E> { 37 private val listeners = CopyOnWriteArrayList<NamedListener>() 38 39 override val size: Int 40 get() = listeners.size 41 isEmptynull42 override fun isEmpty() = listeners.isEmpty() 43 44 override fun iterator(): Iterator<E> = iterator { 45 listeners.iterator().forEach { yield(it.listener) } 46 } 47 containsAllnull48 override fun containsAll(elements: Collection<E>) = 49 listeners.count { it.listener in elements } == elements.size 50 <lambda>null51 override fun contains(element: E) = listeners.firstOrNull { it.listener == element } != null 52 addIfAbsentnull53 override fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(NamedListener(element)) 54 55 override fun remove(element: E): Boolean = listeners.removeIf { it.listener == element } 56 57 /** A wrapper for the listener with an associated name. */ 58 inner class NamedListener(val listener: E) { 59 val name: String = getName(listener) 60 hashCodenull61 override fun hashCode(): Int { 62 return listener.hashCode() 63 } 64 equalsnull65 override fun equals(other: Any?): Boolean = 66 when { 67 other === null -> false 68 other === this -> true 69 other !is NamedListenerSet<*>.NamedListener -> false 70 listener == other.listener -> true 71 else -> false 72 } 73 } 74 75 /** Iterate the listeners in the set, providing the name for each one as well. */ forEachNamednull76 inline fun forEachNamed(block: (String, E) -> Unit) = 77 namedIterator().forEach { element -> block(element.name, element.listener) } 78 79 /** 80 * Iterate the listeners in the set, wrapping each call to the block with [traceSection] using 81 * the listener name. 82 */ namenull83 inline fun forEachTraced(block: (E) -> Unit) = forEachNamed { name, listener -> 84 traceSection(name) { block(listener) } 85 } 86 87 /** 88 * Iterate the listeners in the set, wrapping each call to the block with [traceSection] using 89 * the listener name. 90 */ namenull91 fun forEachTraced(consumer: Consumer<E>) = forEachNamed { name, listener -> 92 traceSection(name) { consumer.accept(listener) } 93 } 94 95 /** Iterate over the [NamedListener]s currently in the set. */ namedIteratornull96 fun namedIterator(): Iterator<NamedListener> = listeners.iterator() 97 } 98