diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index a8da554d7e1f8..905a5f943f0de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -44,6 +44,8 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; +import androidx.lifecycle.ViewTreeLifecycleOwner; + import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -52,6 +54,7 @@ import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.lifecycle.WindowAddedViewLifecycleOwner; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -241,6 +244,16 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; mWindowManager.addView(mNotificationShadeView, mLp); + + // Set up and "inject" a LifecycleOwner bound to the Window-View relationship such that all + // views in the sub-tree rooted under this view can access the LifecycleOwner using + // ViewTreeLifecycleOwner.get(...). + if (ViewTreeLifecycleOwner.get(mNotificationShadeView) == null) { + ViewTreeLifecycleOwner.set( + mNotificationShadeView, + new WindowAddedViewLifecycleOwner(mNotificationShadeView)); + } + mLpChanged.copyFrom(mLp); onThemeChanged(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java index c402d2e47cf35..0e42d9a576f78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java @@ -28,8 +28,10 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -42,6 +44,8 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.View; import android.view.WindowManager; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ViewTreeLifecycleOwner; import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; @@ -61,6 +65,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -69,7 +74,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Mock private WindowManager mWindowManager; @Mock private DozeParameters mDozeParameters; - @Mock private NotificationShadeWindowView mNotificationShadeWindowView; + @Spy private final NotificationShadeWindowView mNotificationShadeWindowView = spy( + new NotificationShadeWindowView(mContext, null)); @Mock private IActivityManager mActivityManager; @Mock private SysuiStatusBarStateController mStatusBarStateController; @Mock private ConfigurationController mConfigurationController; @@ -85,6 +91,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { private NotificationShadeWindowControllerImpl mNotificationShadeWindowController; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -176,6 +183,24 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { verify(mWindowManager, never()).updateViewLayout(any(), mLayoutParameters.capture()); } + @Test + public void attach_setsUpLifecycleOwner() { + mNotificationShadeWindowController.attach(); + + assertThat(ViewTreeLifecycleOwner.get(mNotificationShadeWindowView)).isNotNull(); + } + + @Test + public void attach_doesNotSetUpLifecycleOwnerIfAlreadySet() { + final LifecycleOwner previouslySet = mock(LifecycleOwner.class); + ViewTreeLifecycleOwner.set(mNotificationShadeWindowView, previouslySet); + + mNotificationShadeWindowController.attach(); + + assertThat(ViewTreeLifecycleOwner.get(mNotificationShadeWindowView)) + .isEqualTo(previouslySet); + } + @Test public void setScrimsVisibility_earlyReturn() { clearInvocations(mWindowManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 2e58fc4f93fa5..2a7feb02abf78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -71,6 +71,7 @@ import android.testing.TestableLooper; import android.util.Pair; import android.util.SparseArray; import android.view.View; +import android.view.ViewTreeObserver; import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -265,6 +266,8 @@ public class BubblesTest extends SysuiTestCase { ShellExecutor syncExecutor = new SyncExecutor(); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + when(mNotificationShadeWindowView.getViewTreeObserver()) + .thenReturn(mock(ViewTreeObserver.class)); mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,