Merge "Fix flicker of QS footer actions when restarting SystemUI (1/2)" into udc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 09cc2c5..cce708e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -120,6 +120,7 @@
private final QSLogger mLogger;
private final FooterActionsController mFooterActionsController;
private final FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
+ private final FooterActionsViewBinder mFooterActionsViewBinder;
private final ListeningAndVisibilityLifecycleOwner mListeningAndVisibilityLifecycleOwner;
private boolean mShowCollapsedOnKeyguard;
private boolean mLastKeyguardAndExpanded;
@@ -177,6 +178,7 @@
DumpManager dumpManager, QSLogger qsLogger,
FooterActionsController footerActionsController,
FooterActionsViewModel.Factory footerActionsViewModelFactory,
+ FooterActionsViewBinder footerActionsViewBinder,
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
FeatureFlags featureFlags) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
@@ -193,6 +195,7 @@
mDumpManager = dumpManager;
mFooterActionsController = footerActionsController;
mFooterActionsViewModelFactory = footerActionsViewModelFactory;
+ mFooterActionsViewBinder = footerActionsViewBinder;
mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
}
@@ -285,7 +288,7 @@
if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
Log.d(TAG, "Binding the View implementation of the QS footer actions");
- FooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
+ mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
mListeningAndVisibilityLifecycleOwner);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 1921586..9c9ad33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -33,27 +33,27 @@
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.binder.IconViewBinder
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.people.ui.view.PeopleViewBinder.bind
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import javax.inject.Inject
import kotlin.math.roundToInt
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/** A ViewBinder for [FooterActionsViewBinder]. */
-object FooterActionsViewBinder {
+@SysUISingleton
+class FooterActionsViewBinder @Inject constructor() {
/** Create a view that can later be [bound][bind] to a [FooterActionsViewModel]. */
- @JvmStatic
fun create(context: Context): LinearLayout {
return LayoutInflater.from(context).inflate(R.layout.footer_actions, /* root= */ null)
as LinearLayout
}
/** Bind [view] to [viewModel]. */
- @JvmStatic
fun bind(
view: LinearLayout,
viewModel: FooterActionsViewModel,
@@ -98,6 +98,11 @@
var previousForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
var previousUserSwitcher: FooterActionsButtonViewModel? = null
+ // Set the initial visibility on the View directly so that we don't briefly show it for a
+ // few frames before [viewModel.isVisible] is collected.
+ view.isInvisible = !viewModel.isVisible.value
+
+ // Listen for ViewModel updates when the View is attached.
view.repeatWhenAttached {
val attachedScope = this.lifecycleScope
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 3a9098a..b3596a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -64,7 +64,7 @@
* the UI should still participate to the layout it is included in (i.e. in the View world it
* should be INVISIBLE, not GONE).
*/
- private val _isVisible = MutableStateFlow(true)
+ private val _isVisible = MutableStateFlow(false)
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
/** The alpha the UI rendering this ViewModel should have. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 0ab0e2b..87ca9df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -106,6 +106,7 @@
@Mock private QSSquishinessController mSquishinessController;
@Mock private FooterActionsViewModel mFooterActionsViewModel;
@Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
+ @Mock private FooterActionsViewBinder mFooterActionsViewBinder;
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
@Mock private FeatureFlags mFeatureFlags;
private View mQsFragmentView;
@@ -558,6 +559,7 @@
mock(QSLogger.class),
mock(FooterActionsController.class),
mFooterActionsViewModelFactory,
+ mFooterActionsViewBinder,
mLargeScreenShadeInterpolator,
mFeatureFlags);
}
@@ -584,7 +586,7 @@
when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader);
when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext));
when(mQsFragmentView.findViewById(R.id.qs_footer_actions)).thenAnswer(
- invocation -> FooterActionsViewBinder.create(mContext));
+ invocation -> new FooterActionsViewBinder().create(mContext));
}
private void setUpInflater() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 59f0d96..2cc6709 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -376,13 +376,13 @@
@Test
fun isVisible() {
val underTest = utils.footerActionsViewModel()
- assertThat(underTest.isVisible.value).isTrue()
-
- underTest.onVisibilityChangeRequested(visible = false)
assertThat(underTest.isVisible.value).isFalse()
underTest.onVisibilityChangeRequested(visible = true)
assertThat(underTest.isVisible.value).isTrue()
+
+ underTest.onVisibilityChangeRequested(visible = false)
+ assertThat(underTest.isVisible.value).isFalse()
}
@Test