diff options
14 files changed, 376 insertions, 61 deletions
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml index a33be12a655a..cd5c37d43633 100644 --- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml @@ -40,6 +40,7 @@ <ImageView android:src="@*android:drawable/ic_phone" + android:id="@+id/ongoing_activity_chip_icon" android:layout_width="@dimen/ongoing_activity_chip_icon_size" android:layout_height="@dimen/ongoing_activity_chip_icon_size" android:tint="?android:attr/colorPrimary" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt new file mode 100644 index 000000000000..2032ec8af78c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt @@ -0,0 +1,33 @@ +/* + * 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.statusbar.chips.ui.binder + +import com.android.systemui.statusbar.chips.ui.view.ChipChronometer + +object ChipChronometerBinder { + /** + * Updates the given [view] chronometer with a new start time and starts it. + * + * @param startTimeMs the time this event started, relative to + * [com.android.systemui.util.time.SystemClock.elapsedRealtime]. See + * [android.widget.Chronometer.setBase]. + */ + fun bind(startTimeMs: Long, view: ChipChronometer) { + view.base = startTimeMs + view.start() + } +} 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 97f9e066ded5..aac211ae6b46 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 @@ -39,6 +39,7 @@ import com.android.app.animation.Interpolators; import com.android.app.animation.InterpolatorsAndroidX; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dumpable; +import com.android.systemui.Flags; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; @@ -51,7 +52,6 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.OperatorNameView; import com.android.systemui.statusbar.OperatorNameViewController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel; import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState; import com.android.systemui.statusbar.events.SystemStatusAnimationCallback; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; @@ -135,8 +135,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private final CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger; private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory; private final OngoingCallController mOngoingCallController; - // TODO(b/332662551): Use this view model to show the ongoing activity chips. - private final OngoingActivityChipsViewModel mOngoingActivityChipsViewModel; private final SystemStatusAnimationScheduler mAnimationScheduler; private final StatusBarLocationPublisher mLocationPublisher; private final NotificationIconAreaController mNotificationIconAreaController; @@ -207,6 +205,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private boolean mTransitionFromLockscreenToDreamStarted = false; /** + * True if there's an active ongoing activity that should be showing a chip and false otherwise. + */ + private boolean mHasOngoingActivity; + + /** * Listener that updates {@link #mWaitingForWindowStateChangeAfterCameraLaunch} when it receives * a new status bar window state. */ @@ -216,11 +219,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue }; private DisposableHandle mNicBindingDisposable; + private boolean mAnimationsEnabled = true; + @Inject public CollapsedStatusBarFragment( StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, OngoingCallController ongoingCallController, - OngoingActivityChipsViewModel ongoingActivityChipsViewModel, SystemStatusAnimationScheduler animationScheduler, StatusBarLocationPublisher locationPublisher, NotificationIconAreaController notificationIconAreaController, @@ -246,7 +250,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue DemoModeController demoModeController) { mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mOngoingCallController = ongoingCallController; - mOngoingActivityChipsViewModel = ongoingActivityChipsViewModel; mAnimationScheduler = animationScheduler; mLocationPublisher = locationPublisher; mNotificationIconAreaController = notificationIconAreaController; @@ -401,6 +404,17 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue return mBlockedIcons; } + + @VisibleForTesting + void enableAnimationsForTesting() { + mAnimationsEnabled = true; + } + + @VisibleForTesting + void disableAnimationsForTesting() { + mAnimationsEnabled = false; + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -476,7 +490,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue notificationIconArea.addView(mNotificationIconAreaInner); } - updateNotificationIconAreaAndCallChip(/* animate= */ false); + updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false); Trace.endSection(); } @@ -493,15 +507,21 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private StatusBarVisibilityChangeListener mStatusBarVisibilityChangeListener = new StatusBarVisibilityChangeListener() { - @Override - public void onStatusBarVisibilityMaybeChanged() { - updateStatusBarVisibilities(/* animate= */ true); - } + @Override + public void onStatusBarVisibilityMaybeChanged() { + updateStatusBarVisibilities(/* animate= */ true); + } - @Override - public void onTransitionFromLockscreenToDreamStarted() { - mTransitionFromLockscreenToDreamStarted = true; - } + @Override + public void onTransitionFromLockscreenToDreamStarted() { + mTransitionFromLockscreenToDreamStarted = true; + } + + @Override + public void onOngoingActivityStatusChanged(boolean hasOngoingActivity) { + mHasOngoingActivity = hasOngoingActivity; + updateStatusBarVisibilities(/* animate= */ true); + } }; @Override @@ -532,11 +552,14 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } } - // The ongoing call chip and notification icon visibilities are intertwined, so update both - // if either change. - if (newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons() - || newModel.getShowOngoingCallChip() != previousModel.getShowOngoingCallChip()) { - updateNotificationIconAreaAndCallChip(animate); + // The ongoing activity chip and notification icon visibilities are intertwined, so update + // both if either change. + boolean notifsChanged = + newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons(); + boolean ongoingActivityChanged = + newModel.getShowOngoingActivityChip() != previousModel.getShowOngoingActivityChip(); + if (notifsChanged || ongoingActivityChanged) { + updateNotificationIconAreaAndOngoingActivityChip(animate); } // The clock may have already been hidden, but we might want to shift its @@ -566,45 +589,58 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue return new StatusBarVisibilityModel( /* showClock= */ false, /* showNotificationIcons= */ false, - /* showOngoingCallChip= */ false, + /* showOngoingActivityChip= */ false, /* showSystemInfo= */ false); } boolean showClock = externalModel.getShowClock() && !headsUpVisible; - boolean showOngoingCallChip = mOngoingCallController.hasOngoingCall() && !headsUpVisible; + + boolean showOngoingActivityChip; + if (Flags.statusBarScreenSharingChips()) { + // If this flag is on, the ongoing activity status comes from + // CollapsedStatusBarViewBinder, which updates the mHasOngoingActivity variable. + showOngoingActivityChip = mHasOngoingActivity; + } else { + // If this flag is off, the only ongoing activity is the ongoing call, and we pull it + // from the controller directly. + showOngoingActivityChip = mOngoingCallController.hasOngoingCall(); + } + return new StatusBarVisibilityModel( showClock, externalModel.getShowNotificationIcons(), - showOngoingCallChip, + showOngoingActivityChip && !headsUpVisible, externalModel.getShowSystemInfo()); } /** - * Updates the visibility of the notification icon area and ongoing call chip based on disabled1 - * state. + * Updates the visibility of the notification icon area and ongoing activity chip based on + * mLastModifiedVisibility. */ - private void updateNotificationIconAreaAndCallChip(boolean animate) { + private void updateNotificationIconAreaAndOngoingActivityChip(boolean animate) { StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility; boolean disableNotifications = !visibilityModel.getShowNotificationIcons(); - boolean hasOngoingCall = visibilityModel.getShowOngoingCallChip(); + boolean hasOngoingActivity = visibilityModel.getShowOngoingActivityChip(); - // Hide notifications if the disable flag is set or we have an ongoing call. - if (disableNotifications || hasOngoingCall) { - hideNotificationIconArea(animate && !hasOngoingCall); + // Hide notifications if the disable flag is set or we have an ongoing activity. + if (disableNotifications || hasOngoingActivity) { + hideNotificationIconArea(animate && !hasOngoingActivity); } else { showNotificationIconArea(animate); } - // Show the ongoing call chip only if there is an ongoing call *and* notification icons - // are allowed. (The ongoing call chip occupies the same area as the notification icons, - // so if the icons are disabled then the call chip should be, too.) - boolean showOngoingCallChip = hasOngoingCall && !disableNotifications; - if (showOngoingCallChip) { + // Show the ongoing activity chip only if there is an ongoing activity *and* notification + // icons are allowed. (The ongoing activity chip occupies the same area as the notification, + // icons so if the icons are disabled then the activity chip should be, too.) + boolean showOngoingActivityChip = hasOngoingActivity && !disableNotifications; + if (showOngoingActivityChip) { showOngoingActivityChip(animate); } else { hideOngoingActivityChip(animate); } - mOngoingCallController.notifyChipVisibilityChanged(showOngoingCallChip); + if (!Flags.statusBarScreenSharingChips()) { + mOngoingCallController.notifyChipVisibilityChanged(showOngoingActivityChip); + } } private boolean shouldHideStatusBar() { @@ -702,8 +738,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue /** * Displays the ongoing activity chip. * - * For now, this chip will only ever contain the ongoing call information, but after b/332662551 - * feature is implemented, it will support different kinds of ongoing activities. + * If Flags.statusBarScreenSharingChips is disabled, this chip will only ever contain the + * ongoing call information, If that flag is enabled, it will support different kinds of ongoing + * activities. See b/332662551. */ private void showOngoingActivityChip(boolean animate) { animateShow(mOngoingActivityChip, animate); @@ -746,7 +783,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue */ private void animateHiddenState(final View v, int state, boolean animate) { v.animate().cancel(); - if (!animate) { + if (!animate || !mAnimationsEnabled) { v.setAlpha(0f); v.setVisibility(state); return; @@ -773,7 +810,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private void animateShow(View v, boolean animate) { v.animate().cancel(); v.setVisibility(View.VISIBLE); - if (!animate) { + if (!animate || !mAnimationsEnabled) { v.setAlpha(1f); return; } @@ -872,6 +909,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @Override public void dump(PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, /* singleIndent= */" "); + pw.println("mHasOngoingActivity=" + mHasOngoingActivity); + pw.println("mAnimationsEnabled=" + mAnimationsEnabled); StatusBarFragmentComponent component = mStatusBarFragmentComponent; if (component == null) { pw.println("StatusBarFragmentComponent is null"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt index 7cdb9c0a7aa8..0a19023d9e8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt @@ -59,13 +59,13 @@ class CollapsedStatusBarFragmentLogger @Inject constructor( { bool1 = model.showClock bool2 = model.showNotificationIcons - bool3 = model.showOngoingCallChip + bool3 = model.showOngoingActivityChip bool4 = model.showSystemInfo }, { "New visibilities calculated internally. " + "showClock=$bool1 " + "showNotificationIcons=$bool2 " + - "showOngoingCallChip=$bool3 " + + "showOngoingActivityChip=$bool3 " + "showSystemInfo=$bool4" } ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt index cf54cb7aa954..fe24faece1d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt @@ -26,7 +26,7 @@ import android.app.StatusBarManager.DISABLE_SYSTEM_INFO data class StatusBarVisibilityModel( val showClock: Boolean, val showNotificationIcons: Boolean, - val showOngoingCallChip: Boolean, + val showOngoingActivityChip: Boolean, val showSystemInfo: Boolean, ) { companion object { @@ -48,7 +48,7 @@ data class StatusBarVisibilityModel( showNotificationIcons = (disabled1 and DISABLE_NOTIFICATION_ICONS) == 0, // TODO(b/279899176): [CollapsedStatusBarFragment] always overwrites this with the // value of [OngoingCallController]. Do we need to process the flag here? - showOngoingCallChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0, + showOngoingActivityChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0, showSystemInfo = (disabled1 and DISABLE_SYSTEM_INFO) == 0 && (disabled2 and DISABLE2_SYSTEM_ICONS) == 0 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt index 7d7f49bb8d17..a2ec1f21a35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt @@ -19,11 +19,17 @@ package com.android.systemui.statusbar.pipeline.shared.ui.binder import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.view.View +import android.widget.ImageView import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.Flags +import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R +import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel +import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder +import com.android.systemui.statusbar.chips.ui.view.ChipChronometer import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel import javax.inject.Inject @@ -75,6 +81,35 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa } } } + + if (Flags.statusBarScreenSharingChips()) { + val chipView: View = view.requireViewById(R.id.ongoing_activity_chip) + val chipIconView: ImageView = + chipView.requireViewById(R.id.ongoing_activity_chip_icon) + val chipTimeView: ChipChronometer = + chipView.requireViewById(R.id.ongoing_activity_chip_time) + launch { + viewModel.ongoingActivityChip.collect { chipModel -> + when (chipModel) { + is OngoingActivityChipModel.Shown -> { + IconViewBinder.bind(chipModel.icon, chipIconView) + ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView) + // TODO(b/332662551): Attach click listener to chip + + listener.onOngoingActivityStatusChanged( + hasOngoingActivity = true + ) + } + is OngoingActivityChipModel.Hidden -> { + chipTimeView.stop() + listener.onOngoingActivityStatusChanged( + hasOngoingActivity = false + ) + } + } + } + } + } } } } @@ -120,4 +155,7 @@ interface StatusBarVisibilityChangeListener { /** Called when a transition from lockscreen to dream has started. */ fun onTransitionFromLockscreenToDreamStarted() + + /** Called when the status of the ongoing activity chip (active or not active) has changed. */ + fun onOngoingActivityStatusChanged(hasOngoingActivity: Boolean) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt index 0a6e95eee127..bb3a67ed49bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt @@ -24,6 +24,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor @@ -59,6 +61,9 @@ interface CollapsedStatusBarViewModel { /** Emits whenever a transition from lockscreen to dream has started. */ val transitionFromLockscreenToDreamStartedEvent: Flow<Unit> + /** The ongoing activity chip that should be shown on the left-hand side of the status bar. */ + val ongoingActivityChip: StateFlow<OngoingActivityChipModel> + /** * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where * status bar and navigation icons dim. In this mode, a notification dot appears where the @@ -78,6 +83,7 @@ constructor( private val lightsOutInteractor: LightsOutInteractor, private val notificationsInteractor: ActiveNotificationsInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, + ongoingActivityChipsViewModel: OngoingActivityChipsViewModel, @Application coroutineScope: CoroutineScope, ) : CollapsedStatusBarViewModel { override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> = @@ -91,6 +97,8 @@ constructor( .filter { it.transitionState == TransitionState.STARTED } .map {} + override val ongoingActivityChip = ongoingActivityChipsViewModel.chip + override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) { emptyFlow() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt index 1260f07d0ba1..0b0bcbb2de6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt @@ -140,9 +140,11 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() { assertThat(latest).isEqualTo(callChip) } - private fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) { - assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java) - val icon = (latest as OngoingActivityChipModel.Shown).icon - assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record) + companion object { + fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) { + assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java) + val icon = (latest as OngoingActivityChipModel.Shown).icon + assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record) + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt index 87d813c6d19f..e0f1e1a46d3b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt @@ -63,7 +63,7 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() { StatusBarVisibilityModel( showClock = false, showNotificationIcons = true, - showOngoingCallChip = false, + showOngoingActivityChip = false, showSystemInfo = true, ) ) @@ -74,7 +74,7 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() { assertThat(actualString).contains("showClock=false") assertThat(actualString).contains("showNotificationIcons=true") - assertThat(actualString).contains("showOngoingCallChip=false") + assertThat(actualString).contains("showOngoingActivityChip=false") assertThat(actualString).contains("showSystemInfo=true") } } 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 ff182ad4a5ea..ee27cea48565 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 @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone.fragment; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS; import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN; @@ -33,6 +34,8 @@ import android.app.StatusBarManager; import android.content.Context; import android.os.Bundle; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; @@ -46,7 +49,6 @@ import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.animation.AnimatorTestRule; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; -import com.android.systemui.kosmos.KosmosJavaAdapter; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.LogcatEchoTracker; import com.android.systemui.plugins.DarkIconDispatcher; @@ -56,7 +58,6 @@ import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.OperatorNameViewController; -import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel; import com.android.systemui.statusbar.disableflags.DisableFlagsLogger; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder; @@ -92,11 +93,9 @@ import java.util.List; @RunWithLooper(setAsMainLooper = true) @SmallTest public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { - private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(); private NotificationIconAreaController mMockNotificationAreaController; private ShadeExpansionStateManager mShadeExpansionStateManager; private OngoingCallController mOngoingCallController; - private OngoingActivityChipsViewModel mOngoingActivityChipsViewModel; private SystemStatusAnimationScheduler mAnimationScheduler; private StatusBarLocationPublisher mLocationPublisher; // Set in instantiate() @@ -421,6 +420,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_noOngoingCall_chipHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -433,6 +433,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -446,6 +447,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -459,6 +461,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_hasOngoingCallButAlsoHun_chipHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -472,6 +475,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_ongoingCallEnded_chipHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -498,8 +502,11 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + // Enable animations for testing so that we can verify we still aren't animating + fragment.enableAnimationsForTesting(); fragment.disable(DEFAULT_DISPLAY, 0, 0, false); // Ongoing call started @@ -512,6 +519,161 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void screenSharingChipsDisabled_ignoresNewCallback() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + + // WHEN there *is* an ongoing call via old callback + when(mOngoingCallController.hasOngoingCall()).thenReturn(true); + fragment.disable(DEFAULT_DISPLAY, 0, 0, true); + + // WHEN there's *no* ongoing activity via new callback + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ false); + + // THEN the old callback value is used, so the view is shown + assertEquals(View.VISIBLE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + + // WHEN there's *no* ongoing call via old callback + when(mOngoingCallController.hasOngoingCall()).thenReturn(false); + fragment.disable(DEFAULT_DISPLAY, 0, 0, false); + + // WHEN there *is* an ongoing activity via new callback + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + // THEN the old callback value is used, so the view is hidden + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void noOngoingActivity_chipHidden() { + resumeAndGetFragment(); + + // TODO(b/332662551): We *should* be able to just set a value on + // mCollapsedStatusBarViewModel.getOngoingActivityChip() instead of manually invoking the + // listener, but I'm unable to get the fragment to get attached so that the binder starts + // listening to flows. + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ false); + + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void hasOngoingActivity_chipDisplayedAndNotificationIconsHidden() { + resumeAndGetFragment(); + + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + assertEquals(View.VISIBLE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void hasOngoingActivityButNotificationIconsDisabled_chipHidden() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + fragment.disable(DEFAULT_DISPLAY, + StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false); + + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void hasOngoingActivityButAlsoHun_chipHidden() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true); + + fragment.disable(DEFAULT_DISPLAY, 0, 0, false); + + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void ongoingActivityEnded_chipHidden() { + resumeAndGetFragment(); + + // Ongoing activity started + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + assertEquals(View.VISIBLE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + + // Ongoing activity ended + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ false); + + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void hasOngoingActivity_hidesNotifsWithoutAnimation() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + // Enable animations for testing so that we can verify we still aren't animating + fragment.enableAnimationsForTesting(); + + // Ongoing call started + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + // Notification area is hidden without delay + assertEquals(0f, getNotificationAreaView().getAlpha(), 0.01); + assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility()); + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + public void screenSharingChipsEnabled_ignoresOngoingCallController() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + + // WHEN there *is* an ongoing call via old callback + when(mOngoingCallController.hasOngoingCall()).thenReturn(true); + fragment.disable(DEFAULT_DISPLAY, 0, 0, true); + + // WHEN there's *no* ongoing activity via new callback + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ false); + + // THEN the new callback value is used, so the view is hidden + assertEquals(View.GONE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + + // WHEN there's *no* ongoing call via old callback + when(mOngoingCallController.hasOngoingCall()).thenReturn(false); + fragment.disable(DEFAULT_DISPLAY, 0, 0, false); + + // WHEN there *is* an ongoing activity via new callback + mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged( + /* hasOngoingActivity= */ true); + + // THEN the new callback value is used, so the view is shown + assertEquals(View.VISIBLE, + mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility()); + } + + @Test public void disable_isDozing_clockAndSystemInfoVisible() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); when(mStatusBarStateController.isDozing()).thenReturn(true); @@ -670,7 +832,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { MockitoAnnotations.initMocks(this); setUpDaggerComponent(); mOngoingCallController = mock(OngoingCallController.class); - mOngoingActivityChipsViewModel = mKosmos.getOngoingActivityChipsViewModel(); mAnimationScheduler = mock(SystemStatusAnimationScheduler.class); mLocationPublisher = mock(StatusBarLocationPublisher.class); mStatusBarIconController = mock(StatusBarIconController.class); @@ -691,7 +852,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { return new CollapsedStatusBarFragment( mStatusBarFragmentComponentFactory, mOngoingCallController, - mOngoingActivityChipsViewModel, mAnimationScheduler, mLocationPublisher, mMockNotificationAreaController, @@ -773,7 +933,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { private CollapsedStatusBarFragment resumeAndGetFragment() { mFragments.dispatchResume(); processAllMessages(); - return (CollapsedStatusBarFragment) mFragment; + CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment; + fragment.disableAnimationsForTesting(); + return fragment; } private View getUserChipView() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt index 8e789cb2cae6..022b5d295256 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt @@ -36,7 +36,7 @@ class StatusBarVisibilityModelTest : SysuiTestCase() { StatusBarVisibilityModel( showClock = true, showNotificationIcons = true, - showOngoingCallChip = true, + showOngoingActivityChip = true, showSystemInfo = true, ) @@ -72,17 +72,17 @@ class StatusBarVisibilityModelTest : SysuiTestCase() { } @Test - fun createModelFromFlags_ongoingCallChipNotDisabled_showOngoingCallChipTrue() { + fun createModelFromFlags_ongoingCallChipNotDisabled_showOngoingActivityChipTrue() { val result = createModelFromFlags(disabled1 = 0, disabled2 = 0) - assertThat(result.showOngoingCallChip).isTrue() + assertThat(result.showOngoingActivityChip).isTrue() } @Test - fun createModelFromFlags_ongoingCallChipDisabled_showOngoingCallChipFalse() { + fun createModelFromFlags_ongoingCallChipDisabled_showOngoingActivityChipFalse() { val result = createModelFromFlags(disabled1 = DISABLE_ONGOING_CALL_CHIP, disabled2 = 0) - assertThat(result.showOngoingCallChip).isFalse() + assertThat(result.showOngoingActivityChip).isFalse() } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt index 606feab86d58..532c80ee9334 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt @@ -32,6 +32,11 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.assertLogsWtf +import com.android.systemui.screenrecord.data.model.ScreenRecordModel +import com.android.systemui.screenrecord.data.repository.screenRecordRepository +import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel +import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip +import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel import com.android.systemui.statusbar.data.model.StatusBarMode import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository @@ -65,6 +70,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { kosmos.lightsOutInteractor, kosmos.activeNotificationsInteractor, kosmos.keyguardTransitionInteractor, + kosmos.ongoingActivityChipsViewModel, kosmos.applicationCoroutineScope, ) @@ -382,6 +388,20 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { } } + @Test + fun ongoingActivityChip_matchesViewModel() = + testScope.runTest { + val latest by collectLastValue(underTest.ongoingActivityChip) + + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording + + assertIsScreenRecordChip(latest) + + kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing + + assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden) + } + private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) = ActiveNotificationsStore.Builder() .apply { notifications.forEach(::addIndividualNotif) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt index bc50f7967403..c3c9907bc891 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel +import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -27,6 +28,9 @@ class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel { override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>() + override val ongoingActivityChip: MutableStateFlow<OngoingActivityChipModel> = + MutableStateFlow(OngoingActivityChipModel.Hidden) + override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut fun setNotificationLightsOut(lightsOut: Boolean) { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java index e470406499b6..a5819931549d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.when; import android.app.Fragment; import android.app.Instrumentation; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.BaseFragmentTest; import android.testing.DexmakerShareClassLoaderRule; @@ -31,6 +32,7 @@ import com.android.systemui.utils.leaks.LeakCheckedTest.SysuiLeakCheck; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.mockito.Mockito; @@ -43,6 +45,12 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest { @Rule public final SysuiLeakCheck mLeakCheck = new SysuiLeakCheck(); + @ClassRule + public static final SetFlagsRule.ClassRule mSetFlagsClassRule = + new SetFlagsRule.ClassRule( + com.android.systemui.Flags.class); + @Rule public final SetFlagsRule mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule(); + @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); |