diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarBoundsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarBoundsProvider.kt new file mode 100644 index 0000000000000..f5ba399fe51ac --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarBoundsProvider.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 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.statusbar.phone + +import android.graphics.Rect +import android.view.View +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.END_SIDE_CONTENT +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.START_SIDE_CONTENT +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope +import com.android.systemui.util.boundsOnScreen +import javax.inject.Inject +import javax.inject.Named + +/** Provides various bounds within the status bar. */ +@StatusBarFragmentScope +class StatusBarBoundsProvider +@Inject +constructor( + private val changeListeners: Set<@JvmSuppressWildcards BoundsChangeListener>, + @Named(START_SIDE_CONTENT) private val startSideContent: View, + @Named(END_SIDE_CONTENT) private val endSideContent: View, +) : StatusBarFragmentComponent.Startable { + + interface BoundsChangeListener { + fun onStatusBarBoundsChanged() + } + + private var previousBounds = + BoundsPair(start = startSideContent.boundsOnScreen, end = endSideContent.boundsOnScreen) + + private val layoutListener = + View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + val newBounds = BoundsPair(start = visibleStartSideBounds, end = visibleEndSideBounds) + if (previousBounds != newBounds) { + previousBounds = newBounds + changeListeners.forEach { it.onStatusBarBoundsChanged() } + } + } + + override fun start() { + startSideContent.addOnLayoutChangeListener(layoutListener) + endSideContent.addOnLayoutChangeListener(layoutListener) + } + + override fun stop() { + startSideContent.removeOnLayoutChangeListener(layoutListener) + endSideContent.removeOnLayoutChangeListener(layoutListener) + } + + /** + * Returns the bounds of the end side of the status bar that are visible to the user. The end + * side is right when in LTR and is left when in RTL. + * + * Note that even though the layout might be larger, here we only return the bounds for what is + * visible to the user. + * + * The end side of the status bar contains the multi-user switcher and status icons such as + * wi-fi, battery, etc + */ + val visibleEndSideBounds: Rect + get() = endSideContent.boundsOnScreen + + /** + * Returns the bounds of the start side of the status bar that are visible to the user. The + * start side is left when in LTR and is right when in RTL. + * + * Note that even though the layout might be larger, here we only return the bounds for what is + * visible to the user. + * + * The start side of the status bar contains the operator name, clock, on-going call chip, and + * notifications. + */ + val visibleStartSideBounds: Rect + get() = startSideContent.boundsOnScreen +} + +private data class BoundsPair(val start: Rect, val end: Rect) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 41df8e3cbb319..88e985f9eeaf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -30,6 +30,7 @@ import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.biometrics.AuthRippleView; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -269,7 +270,8 @@ public abstract class StatusBarViewModule { CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, OperatorNameViewController.Factory operatorNameViewControllerFactory, SecureSettings secureSettings, - @Main Executor mainExecutor + @Main Executor mainExecutor, + DumpManager dumpManager ) { return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory, ongoingCallController, @@ -289,7 +291,8 @@ public abstract class StatusBarViewModule { collapsedStatusBarFragmentLogger, operatorNameViewControllerFactory, secureSettings, - mainExecutor); + mainExecutor, + dumpManager); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 39bf92a4dcbb6..0848729781bdc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -34,6 +34,8 @@ import android.os.Parcelable; import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; +import android.util.ArrayMap; +import android.util.IndentingPrintWriter; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; @@ -43,9 +45,11 @@ import android.widget.LinearLayout; import androidx.annotation.VisibleForTesting; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; @@ -66,6 +70,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; import com.android.systemui.statusbar.phone.StatusBarLocationPublisher; import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; @@ -76,9 +81,12 @@ import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListen import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener; import com.android.systemui.util.settings.SecureSettings; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -89,7 +97,7 @@ import java.util.concurrent.Executor; @SuppressLint("ValidFragment") public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks, StatusBarStateController.StateListener, - SystemStatusAnimationCallback { + SystemStatusAnimationCallback, Dumpable { public static final String TAG = "CollapsedStatusBarFragment"; private static final String EXTRA_PANEL_STATE = "panel_state"; @@ -124,8 +132,10 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; private final SecureSettings mSecureSettings; private final Executor mMainExecutor; + private final DumpManager mDumpManager; private List mBlockedIcons = new ArrayList<>(); + private Map mStartableStates = new ArrayMap<>(); private SignalCallback mSignalCallback = new SignalCallback() { @Override @@ -185,7 +195,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, OperatorNameViewController.Factory operatorNameViewControllerFactory, SecureSettings secureSettings, - @Main Executor mainExecutor + @Main Executor mainExecutor, + DumpManager dumpManager ) { mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mOngoingCallController = ongoingCallController; @@ -206,6 +217,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; mSecureSettings = secureSettings; mMainExecutor = mainExecutor; + mDumpManager = dumpManager; } @Override @@ -217,8 +229,15 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + mDumpManager.registerDumpable(getClass().getSimpleName(), this); mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this); mStatusBarFragmentComponent.init(); + mStartableStates.clear(); + for (Startable startable : mStatusBarFragmentComponent.getStartables()) { + mStartableStates.put(startable, Startable.State.STARTING); + startable.start(); + mStartableStates.put(startable, Startable.State.STARTED); + } mStatusBar = (PhoneStatusBarView) view; View contents = mStatusBar.findViewById(R.id.status_bar_contents); @@ -321,6 +340,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } mCarrierConfigTracker.removeCallback(mCarrierConfigCallback); mCarrierConfigTracker.removeDataSubscriptionChangedListener(mDefaultDataListener); + + for (Startable startable : mStatusBarFragmentComponent.getStartables()) { + mStartableStates.put(startable, Startable.State.STOPPING); + startable.stop(); + mStartableStates.put(startable, Startable.State.STOPPED); + } + mDumpManager.unregisterDumpable(getClass().getSimpleName()); } /** Initializes views related to the notification icon area. */ @@ -670,4 +696,23 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue updateStatusBarLocation(left, right); } }; + + @Override + public void dump(PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, /* singleIndent= */" "); + StatusBarFragmentComponent component = mStatusBarFragmentComponent; + if (component == null) { + pw.println("StatusBarFragmentComponent is null"); + } else { + Set startables = component.getStartables(); + pw.println("Startables: " + startables.size()); + pw.increaseIndent(); + for (Startable startable : startables) { + Startable.State startableState = mStartableStates.getOrDefault(startable, + Startable.State.NONE); + pw.println(startable + ", state: " + startableState); + } + pw.decreaseIndent(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java index 6717bc768fbba..d9a58442d856d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java @@ -23,9 +23,12 @@ import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; +import com.android.systemui.statusbar.phone.StatusBarBoundsProvider; import com.android.systemui.statusbar.phone.StatusBarDemoMode; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; +import java.util.Set; + import dagger.BindsInstance; import dagger.Subcomponent; @@ -41,7 +44,10 @@ import dagger.Subcomponent; * should be included here or in {@link StatusBarFragmentModule}. */ -@Subcomponent(modules = {StatusBarFragmentModule.class}) +@Subcomponent(modules = { + StatusBarFragmentModule.class, + StatusBarStartablesModule.class +}) @StatusBarFragmentScope public interface StatusBarFragmentComponent { /** Simple factory. */ @@ -51,6 +57,18 @@ public interface StatusBarFragmentComponent { @BindsInstance CollapsedStatusBarFragment collapsedStatusBarFragment); } + /** + * Performs initialization logic after {@link StatusBarFragmentComponent} has been constructed. + */ + interface Startable { + void start(); + void stop(); + + enum State { + NONE, STARTING, STARTED, STOPPING, STOPPED + } + } + /** * Initialize anything extra for the component. Must be called after the component is created. */ @@ -92,4 +110,10 @@ public interface StatusBarFragmentComponent { /** */ @StatusBarFragmentScope PhoneStatusBarTransitions getPhoneStatusBarTransitions(); + + /** */ + Set getStartables(); + + /** */ + StatusBarBoundsProvider getBoundsProvider(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java index 7252dfb76c142..41f1f9589ce4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java @@ -26,6 +26,7 @@ import com.android.systemui.statusbar.HeadsUpStatusBarView; import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; +import com.android.systemui.statusbar.phone.StatusBarBoundsProvider; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer; import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController; @@ -34,12 +35,14 @@ import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.window.StatusBarWindowController; import java.util.Optional; +import java.util.Set; import javax.inject.Named; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.Multibinds; /** Dagger module for {@link StatusBarFragmentComponent}. */ @Module @@ -48,6 +51,8 @@ public interface StatusBarFragmentModule { String LIGHTS_OUT_NOTIF_VIEW = "lights_out_notif_view"; String OPERATOR_NAME_VIEW = "operator_name_view"; String OPERATOR_NAME_FRAME_VIEW = "operator_name_frame_view"; + String START_SIDE_CONTENT = "start_side_content"; + String END_SIDE_CONTENT = "end_side_content"; /** */ @Provides @@ -65,6 +70,22 @@ public interface StatusBarFragmentModule { return view.findViewById(R.id.battery); } + /** */ + @Provides + @StatusBarFragmentScope + @Named(START_SIDE_CONTENT) + static View startSideContent(@RootView PhoneStatusBarView view) { + return view.findViewById(R.id.status_bar_start_side_content); + } + + /** */ + @Provides + @StatusBarFragmentScope + @Named(END_SIDE_CONTENT) + static View endSideContent(@RootView PhoneStatusBarView view) { + return view.findViewById(R.id.status_bar_end_side_content); + } + /** */ @Provides @StatusBarFragmentScope @@ -138,4 +159,8 @@ public interface StatusBarFragmentModule { static HeadsUpStatusBarView providesHeasdUpStatusBarView(@RootView PhoneStatusBarView view) { return view.findViewById(R.id.heads_up_status_bar_view); } + + /** */ + @Multibinds + Set boundsChangeListeners(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarStartablesModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarStartablesModule.kt new file mode 100644 index 0000000000000..9003d13df0a0e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarStartablesModule.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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.statusbar.phone.fragment.dagger + +import com.android.systemui.statusbar.phone.StatusBarBoundsProvider +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoSet + +@Module +internal interface StatusBarStartablesModule { + + @Binds + @IntoSet + fun statusBarBoundsCalculator( + statusBarBoundsProvider: StatusBarBoundsProvider + ): StatusBarFragmentComponent.Startable +} diff --git a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt index 57b3f53c48fec..ec7aabb58b49b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt +++ b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt @@ -16,7 +16,9 @@ package com.android.systemui.util +import android.graphics.Rect import android.util.IndentingPrintWriter +import android.view.View import android.view.ViewGroup import java.io.PrintWriter @@ -45,4 +47,12 @@ inline fun PrintWriter.indentIfPossible(block: PrintWriter.() -> Unit) { if (this is IndentingPrintWriter) increaseIndent() block() if (this is IndentingPrintWriter) decreaseIndent() -} \ No newline at end of file +} + +/** Convenience extension property for [View.getBoundsOnScreen]. */ +val View.boundsOnScreen: Rect + get() { + val bounds = Rect() + getBoundsOnScreen(bounds) + return bounds + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt new file mode 100644 index 0000000000000..d84010dc77714 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 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.statusbar.phone + +import android.graphics.Rect +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.View +import android.widget.FrameLayout +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.phone.StatusBarBoundsProvider.BoundsChangeListener +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.never +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@RunWithLooper(setAsMainLooper = true) +@SmallTest +class StatusBarBoundsProviderTest : SysuiTestCase() { + + companion object { + private val START_SIDE_BOUNDS = Rect(50, 100, 150, 200) + private val END_SIDE_BOUNDS = Rect(250, 300, 350, 400) + } + + @Mock private lateinit var boundsChangeListener: BoundsChangeListener + + private lateinit var boundsProvider: StatusBarBoundsProvider + + private lateinit var startSideContent: View + private lateinit var endSideContent: View + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + startSideContent = spy(FrameLayout(context)).apply { setBoundsOnScreen(START_SIDE_BOUNDS) } + endSideContent = spy(FrameLayout(context)).apply { setBoundsOnScreen(END_SIDE_BOUNDS) } + + boundsProvider = + StatusBarBoundsProvider(setOf(boundsChangeListener), startSideContent, endSideContent) + } + + @Test + fun visibleStartSideBounds_returnsBoundsFromStartSideContentView() { + assertThat(boundsProvider.visibleStartSideBounds).isEqualTo(START_SIDE_BOUNDS) + } + + @Test + fun visibleEndSideBounds_returnsBoundsFromEndSideContentView() { + assertThat(boundsProvider.visibleEndSideBounds).isEqualTo(END_SIDE_BOUNDS) + } + + @Test + fun startBoundsChange_afterStart_notifiesListener() { + boundsProvider.start() + val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 } + + startSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener).onStatusBarBoundsChanged() + } + + @Test + fun startBoundsChange_beforeStart_doesNotNotifyListener() { + val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 } + + startSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } + + @Test + fun startBoundsChange_afterStop_doesNotNotifyListener() { + boundsProvider.start() + boundsProvider.stop() + val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 } + + startSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } + + @Test + fun startLayoutChange_afterStart_boundsOnScreenSame_doesNotNotifyListener() { + boundsProvider.start() + val newBounds = Rect(START_SIDE_BOUNDS).apply { left += 1 } + + startSideContent.layout(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } + + @Test + fun endBoundsChange_afterStart_notifiesListener() { + boundsProvider.start() + val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 } + + endSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener).onStatusBarBoundsChanged() + } + + @Test + fun endBoundsChange_beforeStart_doesNotNotifyListener() { + val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 } + + endSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } + + @Test + fun endBoundsChange_afterStop_doesNotNotifyListener() { + boundsProvider.start() + boundsProvider.stop() + val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 } + + endSideContent.setBoundsOnScreen(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } + + @Test + fun endLayoutChange_afterStart_boundsOnScreenSame_doesNotNotifyListener() { + boundsProvider.start() + val newBounds = Rect(START_SIDE_BOUNDS).apply { right += 1 } + + endSideContent.layout(newBounds) + + verify(boundsChangeListener, never()).onStatusBarBoundsChanged() + } +} + +private fun View.setBoundsOnScreen(bounds: Rect) { + doAnswer { invocation -> + val boundsOutput = invocation.arguments[0] as Rect + boundsOutput.set(bounds) + return@doAnswer Unit + } + .`when`(this) + .getBoundsOnScreen(any()) + layout(bounds.left, bounds.top, bounds.right, bounds.bottom) +} + +private fun View.layout(rect: Rect) { + layout(rect.left, rect.top, rect.right, rect.bottom) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index 681e998ac9e33..56804d58d2413 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -41,6 +41,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.LogcatEchoTracker; @@ -107,6 +108,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { private NotificationPanelViewController mNotificationPanelViewController; @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; + @Mock + private DumpManager mDumpManager; public CollapsedStatusBarFragmentTest() { super(CollapsedStatusBarFragment.class); @@ -386,7 +389,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { ), mOperatorNameViewControllerFactory, mSecureSettings, - mExecutor); + mExecutor, + mDumpManager); } private void setUpDaggerComponent() {