Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/PrivacyDotWindowControllerTest.kt +15 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,21 @@ class PrivacyDotWindowControllerTest : SysuiTestCase() { assertThat(windowManager.addedViews).isEmpty() } @Test fun onStop_removingWindowViewsThrows_codeDoesNotCrash() { underTest.start() executor.runAllReady() viewController.showingListener?.onPrivacyDotShown(viewController.topLeft) executor.runAllReady() // Simulate removing a view from window manager outside of our code windowManager.addedViews.clear() // Ensure no crash when stopping and trying to remove an already detached view underTest.stop() executor.runAllReady() } // Helper functions: Note that paramsForView needs to find the *root* view (FrameLayout) // that was added to the window manager, not the inner dotView. private fun paramsForView(dotView: View): WindowManager.LayoutParams { Loading packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt +12 −2 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ constructor( val dotViewContainer = dotViewContainersByView[v] val windowView = dotWindowViewsByCorner.remove(dotViewContainer?.corner) if (windowView != null) { windowManager.removeView(windowView) windowManager.removeViewSafely(windowView) } } } Loading Loading @@ -143,7 +143,9 @@ constructor( } fun stop() { dotWindowViewsByCorner.forEach { windowManager.removeView(it.value) } uiExecutor.execute { dotWindowViewsByCorner.forEach { windowManager.removeViewSafely(it.value) } } } private data class DotViewContainer( Loading @@ -162,6 +164,14 @@ constructor( ): PrivacyDotWindowController } private fun WindowManager.removeViewSafely(view: View) { try { removeView(view) } catch (e: IllegalArgumentException) { Log.e(TAG, "Failed to remove view from window manager.") } } private companion object { const val TAG = "PrivacyDotWindowController" } Loading packages/SystemUI/tests/utils/src/android/view/FakeWindowManager.kt +2 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ class FakeWindowManager(private val context: Context) : WindowManager { override fun removeView(view: View) { addedViews.remove(view) ?: throw IllegalArgumentException("$view not attached to window manager") } override fun updateViewLayout(view: View, params: ViewGroup.LayoutParams) { Loading @@ -49,7 +50,7 @@ class FakeWindowManager(private val context: Context) : WindowManager { } override fun removeViewImmediate(view: View) { addedViews.remove(view) removeView(view) } override fun requestAppKeyboardShortcuts( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/PrivacyDotWindowControllerTest.kt +15 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,21 @@ class PrivacyDotWindowControllerTest : SysuiTestCase() { assertThat(windowManager.addedViews).isEmpty() } @Test fun onStop_removingWindowViewsThrows_codeDoesNotCrash() { underTest.start() executor.runAllReady() viewController.showingListener?.onPrivacyDotShown(viewController.topLeft) executor.runAllReady() // Simulate removing a view from window manager outside of our code windowManager.addedViews.clear() // Ensure no crash when stopping and trying to remove an already detached view underTest.stop() executor.runAllReady() } // Helper functions: Note that paramsForView needs to find the *root* view (FrameLayout) // that was added to the window manager, not the inner dotView. private fun paramsForView(dotView: View): WindowManager.LayoutParams { Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt +12 −2 Original line number Diff line number Diff line Loading @@ -96,7 +96,7 @@ constructor( val dotViewContainer = dotViewContainersByView[v] val windowView = dotWindowViewsByCorner.remove(dotViewContainer?.corner) if (windowView != null) { windowManager.removeView(windowView) windowManager.removeViewSafely(windowView) } } } Loading Loading @@ -143,7 +143,9 @@ constructor( } fun stop() { dotWindowViewsByCorner.forEach { windowManager.removeView(it.value) } uiExecutor.execute { dotWindowViewsByCorner.forEach { windowManager.removeViewSafely(it.value) } } } private data class DotViewContainer( Loading @@ -162,6 +164,14 @@ constructor( ): PrivacyDotWindowController } private fun WindowManager.removeViewSafely(view: View) { try { removeView(view) } catch (e: IllegalArgumentException) { Log.e(TAG, "Failed to remove view from window manager.") } } private companion object { const val TAG = "PrivacyDotWindowController" } Loading
packages/SystemUI/tests/utils/src/android/view/FakeWindowManager.kt +2 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ class FakeWindowManager(private val context: Context) : WindowManager { override fun removeView(view: View) { addedViews.remove(view) ?: throw IllegalArgumentException("$view not attached to window manager") } override fun updateViewLayout(view: View, params: ViewGroup.LayoutParams) { Loading @@ -49,7 +50,7 @@ class FakeWindowManager(private val context: Context) : WindowManager { } override fun removeViewImmediate(view: View) { addedViews.remove(view) removeView(view) } override fun requestAppKeyboardShortcuts( Loading