Merge changes Ic3ce1b9d,I5f4b9817 into main
* changes:
[SB][Screen Chips] Add share-to-app and cast-to-other-device chips.
[SB][Screen Chips] Hook up new chip flow to CollapsedStatusBarFragment.
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index a33be12..cd5c37d 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/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
new file mode 100644
index 0000000..ac16d26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.mediaprojection.domain.interactor
+
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Interactor for media-projection-related chips in the status bar.
+ *
+ * There are two kinds of media projection events that will show chips in the status bar:
+ * 1) Share-to-app: Sharing your phone screen content to another app on the same device. (Triggered
+ * from within each individual app.)
+ * 2) Cast-to-other-device: Sharing your phone screen content to a different device. (Triggered from
+ * the Quick Settings Cast tile or from the Settings app.) This interactor handles both of those
+ * event types (though maybe not audio-only casting -- see b/342169876).
+ */
+@SysUISingleton
+class MediaProjectionChipInteractor
+@Inject
+constructor(
+ @Application scope: CoroutineScope,
+ mediaProjectionRepository: MediaProjectionRepository,
+ val systemClock: SystemClock,
+) : OngoingActivityChipInteractor {
+ override val chip: StateFlow<OngoingActivityChipModel> =
+ mediaProjectionRepository.mediaProjectionState
+ .map { state ->
+ when (state) {
+ is MediaProjectionState.NotProjecting -> OngoingActivityChipModel.Hidden
+ is MediaProjectionState.EntireScreen,
+ is MediaProjectionState.SingleTask -> {
+ // TODO(b/332662551): Distinguish between cast-to-other-device and
+ // share-to-app.
+ OngoingActivityChipModel.Shown(
+ icon =
+ Icon.Resource(
+ R.drawable.ic_cast_connected,
+ ContentDescription.Resource(R.string.accessibility_casting)
+ ),
+ // TODO(b/332662551): See if we can use a MediaProjection API to fetch
+ // this time.
+ startTimeMs = systemClock.elapsedRealtime()
+ ) {
+ // TODO(b/332662551): Implement the pause dialog.
+ }
+ }
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index bff5686..585ff5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -34,7 +34,7 @@
/** Interactor for the screen recording chip shown in the status bar. */
@SysUISingleton
-open class ScreenRecordChipInteractor
+class ScreenRecordChipInteractor
@Inject
constructor(
@Application scope: CoroutineScope,
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 0000000..2032ec8
--- /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/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 208eb50..edb2983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -20,6 +20,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -40,6 +41,7 @@
constructor(
@Application scope: CoroutineScope,
screenRecordChipInteractor: ScreenRecordChipInteractor,
+ mediaProjectionChipInteractor: MediaProjectionChipInteractor,
callChipInteractor: CallChipInteractor,
) {
@@ -51,10 +53,19 @@
* actually displaying the chip.
*/
val chip: StateFlow<OngoingActivityChipModel> =
- combine(screenRecordChipInteractor.chip, callChipInteractor.chip) { screenRecord, call ->
+ combine(
+ screenRecordChipInteractor.chip,
+ mediaProjectionChipInteractor.chip,
+ callChipInteractor.chip
+ ) { screenRecord, mediaProjection, call ->
// This `when` statement shows the priority order of the chips
when {
+ // Screen recording also activates the media projection APIs, so whenever the
+ // screen recording chip is active, the media projection chip would also be
+ // active. We want the screen-recording-specific chip shown in this case, so we
+ // give the screen recording chip priority. See b/296461748.
screenRecord is OngoingActivityChipModel.Shown -> screenRecord
+ mediaProjection is OngoingActivityChipModel.Shown -> mediaProjection
else -> call
}
}
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 97f9e06..aac211a 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.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.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 @@
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 @@
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 @@
};
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 @@
DemoModeController demoModeController) {
mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
mOngoingCallController = ongoingCallController;
- mOngoingActivityChipsViewModel = ongoingActivityChipsViewModel;
mAnimationScheduler = animationScheduler;
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
@@ -401,6 +404,17 @@
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 @@
notificationIconArea.addView(mNotificationIconAreaInner);
}
- updateNotificationIconAreaAndCallChip(/* animate= */ false);
+ updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false);
Trace.endSection();
}
@@ -493,15 +507,21 @@
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 @@
}
}
- // 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 @@
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 @@
/**
* 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 @@
*/
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 @@
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 @@
@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 7cdb9c0..0a19023 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 @@
{
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 cf54cb7..fe24fae 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 @@
data class StatusBarVisibilityModel(
val showClock: Boolean,
val showNotificationIcons: Boolean,
- val showOngoingCallChip: Boolean,
+ val showOngoingActivityChip: Boolean,
val showSystemInfo: Boolean,
) {
companion object {
@@ -48,7 +48,7 @@
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 7d7f49b..a2ec1f2 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 @@
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 @@
}
}
}
+
+ 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 @@
/** 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 0a6e95e..bb3a67e 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.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 @@
/** 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 @@
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 @@
.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/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index ef73e2e..e487780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -28,7 +28,6 @@
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createToken
import com.android.systemui.mediaprojection.taskswitcher.fakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
-import com.android.systemui.mediaprojection.taskswitcher.mediaProjectionManagerRepository
import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -45,7 +44,7 @@
private val fakeMediaProjectionManager = kosmos.fakeMediaProjectionManager
private val fakeActivityTaskManager = kosmos.fakeActivityTaskManager
- private val repo = kosmos.mediaProjectionManagerRepository
+ private val repo = kosmos.realMediaProjectionRepository
@Test
fun switchProjectedTask_stateIsUpdatedWithNewTask() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
new file mode 100644
index 0000000..0f33b9d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.mediaprojection.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.mediaProjectionChipInteractor
+import com.android.systemui.util.time.fakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+
+@SmallTest
+class MediaProjectionChipInteractorTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val testScope = kosmos.testScope
+ private val mediaProjectionRepo = kosmos.fakeMediaProjectionRepository
+ private val systemClock = kosmos.fakeSystemClock
+
+ private val underTest = kosmos.mediaProjectionChipInteractor
+
+ @Test
+ fun chip_notProjectingState_isHidden() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ @Test
+ fun chip_singleTaskState_isShownWithIcon() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.SingleTask(createTask(taskId = 1))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun chip_entireScreenState_isShownWithIcon() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun chip_timeResetsOnEachNewShare() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ systemClock.setElapsedRealtime(1234)
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(1234)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+
+ systemClock.setElapsedRealtime(5678)
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
+ }
+}
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 1260f07..121229c 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
@@ -23,6 +23,9 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
@@ -35,13 +38,20 @@
class OngoingActivityChipsViewModelTest : SysuiTestCase() {
private val kosmos = Kosmos()
+ private val testScope = kosmos.testScope
+
+ private val screenRecordState = kosmos.screenRecordRepository.screenRecordState
+ private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState
+ private val callState = kosmos.callChipInteractor.chip
+
private val underTest = kosmos.ongoingActivityChipsViewModel
@Test
fun chip_allHidden_hidden() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
- kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -50,9 +60,10 @@
@Test
fun chip_screenRecordShow_restHidden_screenRecordShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
- kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -61,15 +72,15 @@
@Test
fun chip_screenRecordShowAndCallShow_screenRecordShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
@@ -77,16 +88,46 @@
}
@Test
- fun chip_screenRecordHideAndCallShown_callShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ fun chip_screenRecordShowAndMediaProjectionShow_screenRecordShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
+ callState.value = OngoingActivityChipModel.Hidden
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertIsScreenRecordChip(latest)
+ }
+
+ @Test
+ fun chip_mediaProjectionShowAndCallShow_mediaProjectionShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ callState.value = callChip
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertIsMediaProjectionChip(latest)
+ }
+
+ @Test
+ fun chip_screenRecordAndMediaProjectionHideAndCallShown_callShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
@@ -95,22 +136,29 @@
@Test
fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
- kosmos.testScope.runTest {
+ testScope.runTest {
// Start with just the lower priority call chip
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ callState.value = callChip
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ screenRecordState.value = ScreenRecordModel.DoingNothing
val latest by collectLastValue(underTest.chip)
assertThat(latest).isEqualTo(callChip)
+ // WHEN the higher priority media projection chip is added
+ mediaProjectionState.value = MediaProjectionState.SingleTask(createTask(taskId = 1))
+
+ // THEN the higher priority media projection chip is used
+ assertIsMediaProjectionChip(latest)
+
// WHEN the higher priority screen record chip is added
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ screenRecordState.value = ScreenRecordModel.Recording
// THEN the higher priority screen record chip is used
assertIsScreenRecordChip(latest)
@@ -118,31 +166,47 @@
@Test
fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
- kosmos.testScope.runTest {
- // Start with both the higher priority screen record chip and lower priority call chip
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ testScope.runTest {
+ // WHEN all chips are active
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
+ // THEN the highest priority screen record is used
assertIsScreenRecordChip(latest)
// WHEN the higher priority screen record is removed
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+
+ // THEN the lower priority media projection is used
+ assertIsMediaProjectionChip(latest)
+
+ // WHEN the higher priority media projection is removed
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
// THEN the lower priority call is used
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)
+ }
+
+ fun assertIsMediaProjectionChip(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.ic_cast_connected)
+ }
}
}
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 87d813c..e0f1e1a 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 @@
StatusBarVisibilityModel(
showClock = false,
showNotificationIcons = true,
- showOngoingCallChip = false,
+ showOngoingActivityChip = false,
showSystemInfo = true,
)
)
@@ -74,7 +74,7 @@
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 ff182ad..ee27cea 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 @@
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.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.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.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 @@
@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 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_noOngoingCall_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -433,6 +433,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -446,6 +447,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -459,6 +461,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCallButAlsoHun_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -472,6 +475,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -498,8 +502,11 @@
}
@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 @@
}
@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 @@
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 @@
return new CollapsedStatusBarFragment(
mStatusBarFragmentComponentFactory,
mOngoingCallController,
- mOngoingActivityChipsViewModel,
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
@@ -773,7 +933,9 @@
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 8e789cb..022b5d2 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 @@
StatusBarVisibilityModel(
showClock = true,
showNotificationIcons = true,
- showOngoingCallChip = true,
+ showOngoingActivityChip = true,
showSystemInfo = true,
)
@@ -72,17 +72,17 @@
}
@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 606feab..c9fe449 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,14 @@
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.assertLogsWtf
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+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.assertIsMediaProjectionChip
+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 +73,7 @@
kosmos.lightsOutInteractor,
kosmos.activeNotificationsInteractor,
kosmos.keyguardTransitionInteractor,
+ kosmos.ongoingActivityChipsViewModel,
kosmos.applicationCoroutineScope,
)
@@ -382,6 +391,25 @@
}
}
+ @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)
+
+ kosmos.fakeMediaProjectionRepository.mediaProjectionState.value =
+ MediaProjectionState.EntireScreen
+
+ assertIsMediaProjectionChip(latest)
+ }
+
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 bc50f79..c3c9907 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 @@
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 e470406..a581993 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 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 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 @@
@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();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
new file mode 100644
index 0000000..c4365c9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.mediaprojection.data.repository
+
+import android.app.ActivityManager
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMediaProjectionRepository : MediaProjectionRepository {
+ override suspend fun switchProjectedTask(task: ActivityManager.RunningTaskInfo) {}
+
+ override val mediaProjectionState: MutableStateFlow<MediaProjectionState> =
+ MutableStateFlow(MediaProjectionState.NotProjecting)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt
new file mode 100644
index 0000000..f253e94
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.mediaprojection.data.repository
+
+import android.os.Handler
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.mediaprojection.taskswitcher.activityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
+
+val Kosmos.fakeMediaProjectionRepository: FakeMediaProjectionRepository by
+ Kosmos.Fixture { FakeMediaProjectionRepository() }
+
+val Kosmos.realMediaProjectionRepository by
+ Kosmos.Fixture {
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = applicationCoroutineScope,
+ tasksRepository = activityTaskManagerTasksRepository,
+ backgroundDispatcher = testDispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
index 5b1f95a..5acadd7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
@@ -16,11 +16,10 @@
package com.android.systemui.mediaprojection.taskswitcher
-import android.os.Handler
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.mediaprojection.data.repository.MediaProjectionManagerRepository
+import com.android.systemui.mediaprojection.data.repository.realMediaProjectionRepository
import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
@@ -40,21 +39,9 @@
)
}
-val Kosmos.mediaProjectionManagerRepository by
- Kosmos.Fixture {
- MediaProjectionManagerRepository(
- mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
- handler = Handler.getMain(),
- applicationScope = applicationCoroutineScope,
- tasksRepository = activityTaskManagerTasksRepository,
- backgroundDispatcher = testDispatcher,
- mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
- )
- }
-
val Kosmos.taskSwitcherInteractor by
Kosmos.Fixture {
- TaskSwitchInteractor(mediaProjectionManagerRepository, activityTaskManagerTasksRepository)
+ TaskSwitchInteractor(realMediaProjectionRepository, activityTaskManagerTasksRepository)
}
val Kosmos.taskSwitcherViewModel by
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 9e02df9..88bde2e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -19,7 +19,9 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import com.android.systemui.util.time.fakeSystemClock
@@ -32,6 +34,15 @@
)
}
+val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
+ Kosmos.Fixture {
+ MediaProjectionChipInteractor(
+ scope = applicationCoroutineScope,
+ mediaProjectionRepository = fakeMediaProjectionRepository,
+ systemClock = fakeSystemClock,
+ )
+ }
+
val Kosmos.callChipInteractor: FakeCallChipInteractor by Kosmos.Fixture { FakeCallChipInteractor() }
val Kosmos.ongoingActivityChipsViewModel: OngoingActivityChipsViewModel by
@@ -39,6 +50,7 @@
OngoingActivityChipsViewModel(
testScope.backgroundScope,
screenRecordChipInteractor = screenRecordChipInteractor,
+ mediaProjectionChipInteractor = mediaProjectionChipInteractor,
callChipInteractor = callChipInteractor,
)
}