Register QS content observers on bg thread
Content observers do Binder calls to register/unregister, use the new async APIs to handle the registration.
Bug: 351766769
Test: created SettingObserverTest
Flag: com.android.systemui.qs_register_setting_observer_on_bg_thread
Change-Id: I3c25365ce7460f1d763223c8a7cc281a2f1be7a7
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index e2ecda3..63ce7eb 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1143,3 +1143,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "systemui"
+ name: "qs_register_setting_observer_on_bg_thread"
+ description: "Registers Quick Settings content providers on background thread"
+ bug: "351766769"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt
new file mode 100644
index 0000000..188f2ac
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 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.qs
+
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.SettingsProxy
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.capture
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SettingObserverTest : SysuiTestCase() {
+
+ private val DEFAULT_VALUE = 7
+
+ @Mock lateinit var settingsProxy: SettingsProxy
+ @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
+
+ private lateinit var testSettingObserver: SettingObserver
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(settingsProxy.getInt(any(), any())).thenReturn(5)
+ whenever(settingsProxy.getUriFor(any())).thenReturn(Uri.parse("content://test_uri"))
+ testSettingObserver =
+ object :
+ SettingObserver(
+ settingsProxy,
+ Handler(Looper.getMainLooper()),
+ "test_setting",
+ DEFAULT_VALUE
+ ) {
+ override fun handleValueChanged(value: Int, observedChange: Boolean) {}
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_true_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ verify(settingsProxy)
+ .registerContentObserverAsync(
+ any<Uri>(),
+ eq(false),
+ eq(testSettingObserver),
+ capture(argumentCaptor)
+ )
+ assertThat(testSettingObserver.value).isEqualTo(5)
+
+ // Verify if the callback applies updated value after the fact
+ whenever(settingsProxy.getInt(any(), any())).thenReturn(12341234)
+ argumentCaptor.value.run()
+ assertThat(testSettingObserver.value).isEqualTo(12341234)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_false_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ reset(settingsProxy)
+ testSettingObserver.isListening = false
+
+ verify(settingsProxy).unregisterContentObserverAsync(eq(testSettingObserver))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_bgFlagDisabled_true_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ verify(settingsProxy)
+ .registerContentObserverSync(any<Uri>(), eq(false), eq(testSettingObserver))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_bgFlagDisabled_false_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ reset(settingsProxy)
+ testSettingObserver.isListening = false
+
+ verify(settingsProxy).unregisterContentObserverSync(eq(testSettingObserver))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
index 6092348..2287f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
@@ -19,6 +19,7 @@
import android.database.ContentObserver;
import android.os.Handler;
+import com.android.systemui.Flags;
import com.android.systemui.statusbar.policy.Listenable;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.settings.SettingsProxy;
@@ -74,10 +75,20 @@
mListening = listening;
if (listening) {
mObservedValue = getValueFromProvider();
- mSettingsProxy.registerContentObserverSync(
- mSettingsProxy.getUriFor(mSettingName), false, this);
+ if (Flags.qsRegisterSettingObserverOnBgThread()) {
+ mSettingsProxy.registerContentObserverAsync(
+ mSettingsProxy.getUriFor(mSettingName), false, this,
+ () -> mObservedValue = getValueFromProvider());
+ } else {
+ mSettingsProxy.registerContentObserverSync(
+ mSettingsProxy.getUriFor(mSettingName), false, this);
+ }
} else {
- mSettingsProxy.unregisterContentObserverSync(this);
+ if (Flags.qsRegisterSettingObserverOnBgThread()) {
+ mSettingsProxy.unregisterContentObserverAsync(this);
+ } else {
+ mSettingsProxy.unregisterContentObserverSync(this);
+ }
mObservedValue = mDefaultValue;
}
}