Adds a DumpController to SystemUI Dependencies
The DumpController allows any SystemUI Dumpable class to subscribe to it
and be dumped during dumpsys of Dependency.
Test: manual (dumpsys Dependency shows "DumpController state)
Test: atest DumpControllerTest
Bug: 129544734
Change-Id: If8d3ec667d99a523e5ae25db84173d9b04b6829c
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 70f2cce..a421940 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -293,6 +293,7 @@
@Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
@Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
@Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
+ @Inject Lazy<DumpController> mDumpController;
@Inject
public Dependency() {
@@ -464,7 +465,7 @@
mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
-
+ mProviders.put(DumpController.class, mDumpController::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
@@ -478,6 +479,11 @@
@Override
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
+
+ // Make sure that the DumpController gets added to mDependencies, as they are only added
+ // with Dependency#get.
+ getDependency(DumpController.class);
+
pw.println("Dumping existing controllers:");
mDependencies.values().stream().filter(obj -> obj instanceof Dumpable)
.forEach(o -> ((Dumpable) o).dump(fd, pw, args));
diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt
new file mode 100644
index 0000000..646abb5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.systemui
+
+import android.util.Log
+import androidx.annotation.GuardedBy
+import com.android.internal.util.Preconditions
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+import javax.inject.Singleton
+
+// TODO: Move all Dumpable dependencies to use DumpController
+/**
+ * Controller that allows any [Dumpable] to subscribe and be dumped along with other SystemUI
+ * dependencies.
+ */
+@Singleton
+class DumpController @Inject constructor() : Dumpable {
+
+ companion object {
+ private const val TAG = "DumpController"
+ private const val DEBUG = false
+ }
+
+ @GuardedBy("listeners")
+ private val listeners = mutableListOf<WeakReference<Dumpable>>()
+ val numListeners: Int
+ get() = listeners.size
+
+ /**
+ * Adds a [Dumpable] listener to be dumped. It will only be added if it is not already tracked.
+ *
+ * @param listener the [Dumpable] to be added
+ */
+ fun addListener(listener: Dumpable) {
+ Preconditions.checkNotNull(listener, "The listener to be added cannot be null")
+ if (DEBUG) Log.v(TAG, "*** register callback for $listener")
+ synchronized<Unit>(listeners) {
+ if (listeners.any { it.get() == listener }) {
+ if (DEBUG) {
+ Log.e(TAG, "Object tried to add another callback")
+ }
+ } else {
+ listeners.add(WeakReference(listener))
+ }
+ }
+ }
+
+ /**
+ * Removes a listener from the list of elements to be dumped.
+ *
+ * @param listener the [Dumpable] to be removed.
+ */
+ fun removeListener(listener: Dumpable) {
+ if (DEBUG) Log.v(TAG, "*** unregister callback for $listener")
+ synchronized(listeners) {
+ listeners.removeAll { it.get() == listener || it.get() == null }
+ }
+ }
+
+ /**
+ * Dump all the [Dumpable] registered with the controller
+ */
+ override fun dump(fd: FileDescriptor?, pw: PrintWriter, args: Array<String>?) {
+ pw.println("DumpController state:")
+ synchronized(listeners) {
+ listeners.forEach { it.get()?.dump(fd, pw, args) }
+ }
+ }
+}