Merge "Fix flicker of QS footer actions when restarting SystemUI (1/2)" into udc-dev

This commit is contained in:
Jordan Demeulenaere
2023-04-24 14:52:01 +00:00
committed by Android (Google) Code Review
5 changed files with 20 additions and 10 deletions

View File

@@ -120,6 +120,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
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 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
DumpManager dumpManager, QSLogger qsLogger,
FooterActionsController footerActionsController,
FooterActionsViewModel.Factory footerActionsViewModelFactory,
FooterActionsViewBinder footerActionsViewBinder,
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
FeatureFlags featureFlags) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
@@ -193,6 +195,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mDumpManager = dumpManager;
mFooterActionsController = footerActionsController;
mFooterActionsViewModelFactory = footerActionsViewModelFactory;
mFooterActionsViewBinder = footerActionsViewBinder;
mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
}
@@ -285,7 +288,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
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;
}

View File

@@ -33,27 +33,27 @@ import androidx.lifecycle.repeatOnLifecycle
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 @@ object FooterActionsViewBinder {
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

View File

@@ -64,7 +64,7 @@ class FooterActionsViewModel(
* 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. */

View File

@@ -106,6 +106,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
@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 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
mock(QSLogger.class),
mock(FooterActionsController.class),
mFooterActionsViewModelFactory,
mFooterActionsViewBinder,
mLargeScreenShadeInterpolator,
mFeatureFlags);
}
@@ -584,7 +586,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
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() {

View File

@@ -376,13 +376,13 @@ class FooterActionsViewModelTest : SysuiTestCase() {
@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