Loading packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +4 −4 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ open class BroadcastDispatcher @Inject constructor ( @Deprecated(message = "Replacing Handler for Executor in SystemUI", replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)")) @JvmOverloads fun registerReceiverWithHandler( open fun registerReceiverWithHandler( receiver: BroadcastReceiver, filter: IntentFilter, handler: Handler, Loading @@ -118,7 +118,7 @@ open class BroadcastDispatcher @Inject constructor ( * categories or the filter has no actions. */ @JvmOverloads fun registerReceiver( open fun registerReceiver( receiver: BroadcastReceiver, filter: IntentFilter, executor: Executor? = context.mainExecutor, Loading Loading @@ -149,7 +149,7 @@ open class BroadcastDispatcher @Inject constructor ( * * @param receiver The receiver to unregister. It will be unregistered for all users. */ fun unregisterReceiver(receiver: BroadcastReceiver) { open fun unregisterReceiver(receiver: BroadcastReceiver) { handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget() } Loading @@ -159,7 +159,7 @@ open class BroadcastDispatcher @Inject constructor ( * @param receiver The receiver to unregister. It will be unregistered for all users. * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL]. */ fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver) .sendToTarget() } Loading packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +16 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.systemui; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading @@ -32,7 +33,10 @@ import androidx.test.InstrumentationRegistry; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.FakeBroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; import org.junit.After; Loading Loading @@ -60,11 +64,14 @@ public abstract class SysuiTestCase { new DexmakerShareClassLoaderRule(); public TestableDependency mDependency; private Instrumentation mRealInstrumentation; private FakeBroadcastDispatcher mFakeBroadcastDispatcher; @Before public void SysuiSetup() throws Exception { SystemUIFactory.createFromConfig(mContext); mDependency = new TestableDependency(mContext); mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class), mock(Looper.class), mock(DumpManager.class)); mRealInstrumentation = InstrumentationRegistry.getInstrumentation(); Instrumentation inst = spy(mRealInstrumentation); Loading @@ -77,12 +84,18 @@ public abstract class SysuiTestCase { "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext"); }); InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments()); // Many tests end up creating a BroadcastDispatcher. Instead, give them a fake that will // record receivers registered. They are not actually leaked as they are kept just as a weak // reference and are never sent to the Context. This will also prevent a real // BroadcastDispatcher from actually registering receivers. mDependency.injectTestDependency(BroadcastDispatcher.class, mFakeBroadcastDispatcher); // A lot of tests get the FalsingManager, often via several layers of indirection. // None of them actually need it. mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake()); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); // TODO: b/151614195 investigate root cause of needing this mock dependency // A lot of tests get the LocalBluetoothManager, often via several layers of indirection. // None of them actually need it. mDependency.injectMockDependency(LocalBluetoothManager.class); } Loading @@ -95,6 +108,8 @@ public abstract class SysuiTestCase { } disallowTestableLooperAsMainThread(); SystemUIFactory.cleanup(); mContext.cleanUpReceivers(this.getClass().getSimpleName()); mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName()); } /** Loading packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java +50 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,24 @@ package com.android.systemui; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.UserHandle; import android.testing.LeakCheck; import android.testing.TestableContext; import android.util.ArraySet; import android.util.Log; import android.view.Display; import java.util.Set; public class SysuiTestableContext extends TestableContext { private Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>(); public SysuiTestableContext(Context base) { super(base); setTheme(R.style.Theme_SystemUI); Loading @@ -40,4 +52,42 @@ public class SysuiTestableContext extends TestableContext { new SysuiTestableContext(getBaseContext().createDisplayContext(display)); return context; } public void cleanUpReceivers(String testName) { Set<BroadcastReceiver> copy = new ArraySet<>(mRegisteredReceivers); for (BroadcastReceiver r : copy) { try { unregisterReceiver(r); Log.w(testName, "Receiver not unregistered from Context: " + r); } catch (IllegalArgumentException e) { // Nothing to do here. Somehow it got unregistered. } } } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { mRegisteredReceivers.add(receiver); return super.registerReceiver(receiver, filter); } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { mRegisteredReceivers.add(receiver); return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); } @Override public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { mRegisteredReceivers.add(receiver); return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler); } @Override public void unregisterReceiver(BroadcastReceiver receiver) { mRegisteredReceivers.remove(receiver); super.unregisterReceiver(receiver); } } packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.broadcast import android.content.BroadcastReceiver import android.content.IntentFilter import android.os.Handler import android.os.Looper import android.os.UserHandle import android.util.ArraySet import android.util.Log import com.android.systemui.SysuiTestableContext import com.android.systemui.dump.DumpManager import java.util.concurrent.Executor class FakeBroadcastDispatcher( context: SysuiTestableContext, handler: Handler, looper: Looper, dumpManager: DumpManager ) : BroadcastDispatcher(context, handler, looper, dumpManager) { private val registeredReceivers = ArraySet<BroadcastReceiver>() override fun registerReceiverWithHandler( receiver: BroadcastReceiver, filter: IntentFilter, handler: Handler, user: UserHandle ) { registeredReceivers.add(receiver) } override fun registerReceiver( receiver: BroadcastReceiver, filter: IntentFilter, executor: Executor?, user: UserHandle ) { registeredReceivers.add(receiver) } override fun unregisterReceiver(receiver: BroadcastReceiver) { registeredReceivers.remove(receiver) } override fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { registeredReceivers.remove(receiver) } fun cleanUpReceivers(testName: String) { registeredReceivers.forEach { Log.i(testName, "Receiver not unregistered from dispatcher: $it") } registeredReceivers.clear() } } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +4 −4 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ open class BroadcastDispatcher @Inject constructor ( @Deprecated(message = "Replacing Handler for Executor in SystemUI", replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)")) @JvmOverloads fun registerReceiverWithHandler( open fun registerReceiverWithHandler( receiver: BroadcastReceiver, filter: IntentFilter, handler: Handler, Loading @@ -118,7 +118,7 @@ open class BroadcastDispatcher @Inject constructor ( * categories or the filter has no actions. */ @JvmOverloads fun registerReceiver( open fun registerReceiver( receiver: BroadcastReceiver, filter: IntentFilter, executor: Executor? = context.mainExecutor, Loading Loading @@ -149,7 +149,7 @@ open class BroadcastDispatcher @Inject constructor ( * * @param receiver The receiver to unregister. It will be unregistered for all users. */ fun unregisterReceiver(receiver: BroadcastReceiver) { open fun unregisterReceiver(receiver: BroadcastReceiver) { handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget() } Loading @@ -159,7 +159,7 @@ open class BroadcastDispatcher @Inject constructor ( * @param receiver The receiver to unregister. It will be unregistered for all users. * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL]. */ fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver) .sendToTarget() } Loading
packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +16 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.systemui; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading @@ -32,7 +33,10 @@ import androidx.test.InstrumentationRegistry; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.FakeBroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; import org.junit.After; Loading Loading @@ -60,11 +64,14 @@ public abstract class SysuiTestCase { new DexmakerShareClassLoaderRule(); public TestableDependency mDependency; private Instrumentation mRealInstrumentation; private FakeBroadcastDispatcher mFakeBroadcastDispatcher; @Before public void SysuiSetup() throws Exception { SystemUIFactory.createFromConfig(mContext); mDependency = new TestableDependency(mContext); mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class), mock(Looper.class), mock(DumpManager.class)); mRealInstrumentation = InstrumentationRegistry.getInstrumentation(); Instrumentation inst = spy(mRealInstrumentation); Loading @@ -77,12 +84,18 @@ public abstract class SysuiTestCase { "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext"); }); InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments()); // Many tests end up creating a BroadcastDispatcher. Instead, give them a fake that will // record receivers registered. They are not actually leaked as they are kept just as a weak // reference and are never sent to the Context. This will also prevent a real // BroadcastDispatcher from actually registering receivers. mDependency.injectTestDependency(BroadcastDispatcher.class, mFakeBroadcastDispatcher); // A lot of tests get the FalsingManager, often via several layers of indirection. // None of them actually need it. mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake()); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); // TODO: b/151614195 investigate root cause of needing this mock dependency // A lot of tests get the LocalBluetoothManager, often via several layers of indirection. // None of them actually need it. mDependency.injectMockDependency(LocalBluetoothManager.class); } Loading @@ -95,6 +108,8 @@ public abstract class SysuiTestCase { } disallowTestableLooperAsMainThread(); SystemUIFactory.cleanup(); mContext.cleanUpReceivers(this.getClass().getSimpleName()); mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName()); } /** Loading
packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java +50 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,24 @@ package com.android.systemui; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.UserHandle; import android.testing.LeakCheck; import android.testing.TestableContext; import android.util.ArraySet; import android.util.Log; import android.view.Display; import java.util.Set; public class SysuiTestableContext extends TestableContext { private Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>(); public SysuiTestableContext(Context base) { super(base); setTheme(R.style.Theme_SystemUI); Loading @@ -40,4 +52,42 @@ public class SysuiTestableContext extends TestableContext { new SysuiTestableContext(getBaseContext().createDisplayContext(display)); return context; } public void cleanUpReceivers(String testName) { Set<BroadcastReceiver> copy = new ArraySet<>(mRegisteredReceivers); for (BroadcastReceiver r : copy) { try { unregisterReceiver(r); Log.w(testName, "Receiver not unregistered from Context: " + r); } catch (IllegalArgumentException e) { // Nothing to do here. Somehow it got unregistered. } } } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { mRegisteredReceivers.add(receiver); return super.registerReceiver(receiver, filter); } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { mRegisteredReceivers.add(receiver); return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); } @Override public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { mRegisteredReceivers.add(receiver); return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler); } @Override public void unregisterReceiver(BroadcastReceiver receiver) { mRegisteredReceivers.remove(receiver); super.unregisterReceiver(receiver); } }
packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.broadcast import android.content.BroadcastReceiver import android.content.IntentFilter import android.os.Handler import android.os.Looper import android.os.UserHandle import android.util.ArraySet import android.util.Log import com.android.systemui.SysuiTestableContext import com.android.systemui.dump.DumpManager import java.util.concurrent.Executor class FakeBroadcastDispatcher( context: SysuiTestableContext, handler: Handler, looper: Looper, dumpManager: DumpManager ) : BroadcastDispatcher(context, handler, looper, dumpManager) { private val registeredReceivers = ArraySet<BroadcastReceiver>() override fun registerReceiverWithHandler( receiver: BroadcastReceiver, filter: IntentFilter, handler: Handler, user: UserHandle ) { registeredReceivers.add(receiver) } override fun registerReceiver( receiver: BroadcastReceiver, filter: IntentFilter, executor: Executor?, user: UserHandle ) { registeredReceivers.add(receiver) } override fun unregisterReceiver(receiver: BroadcastReceiver) { registeredReceivers.remove(receiver) } override fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { registeredReceivers.remove(receiver) } fun cleanUpReceivers(testName: String) { registeredReceivers.forEach { Log.i(testName, "Receiver not unregistered from dispatcher: $it") } registeredReceivers.clear() } } No newline at end of file