Merge "Fix flicker of QS footer actions when restarting SystemUI (1/2)" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
5818342a25
@@ -120,6 +120,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
|||||||
private final QSLogger mLogger;
|
private final QSLogger mLogger;
|
||||||
private final FooterActionsController mFooterActionsController;
|
private final FooterActionsController mFooterActionsController;
|
||||||
private final FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
|
private final FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
|
||||||
|
private final FooterActionsViewBinder mFooterActionsViewBinder;
|
||||||
private final ListeningAndVisibilityLifecycleOwner mListeningAndVisibilityLifecycleOwner;
|
private final ListeningAndVisibilityLifecycleOwner mListeningAndVisibilityLifecycleOwner;
|
||||||
private boolean mShowCollapsedOnKeyguard;
|
private boolean mShowCollapsedOnKeyguard;
|
||||||
private boolean mLastKeyguardAndExpanded;
|
private boolean mLastKeyguardAndExpanded;
|
||||||
@@ -177,6 +178,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
|||||||
DumpManager dumpManager, QSLogger qsLogger,
|
DumpManager dumpManager, QSLogger qsLogger,
|
||||||
FooterActionsController footerActionsController,
|
FooterActionsController footerActionsController,
|
||||||
FooterActionsViewModel.Factory footerActionsViewModelFactory,
|
FooterActionsViewModel.Factory footerActionsViewModelFactory,
|
||||||
|
FooterActionsViewBinder footerActionsViewBinder,
|
||||||
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
|
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
|
||||||
FeatureFlags featureFlags) {
|
FeatureFlags featureFlags) {
|
||||||
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
|
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
|
||||||
@@ -193,6 +195,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
|||||||
mDumpManager = dumpManager;
|
mDumpManager = dumpManager;
|
||||||
mFooterActionsController = footerActionsController;
|
mFooterActionsController = footerActionsController;
|
||||||
mFooterActionsViewModelFactory = footerActionsViewModelFactory;
|
mFooterActionsViewModelFactory = footerActionsViewModelFactory;
|
||||||
|
mFooterActionsViewBinder = footerActionsViewBinder;
|
||||||
mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
|
mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +288,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
|||||||
|
|
||||||
if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
|
if (!ComposeFacade.INSTANCE.isComposeAvailable()) {
|
||||||
Log.d(TAG, "Binding the View implementation of the QS footer actions");
|
Log.d(TAG, "Binding the View implementation of the QS footer actions");
|
||||||
FooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
|
mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
|
||||||
mListeningAndVisibilityLifecycleOwner);
|
mListeningAndVisibilityLifecycleOwner);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,27 +33,27 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.common.ui.binder.IconViewBinder
|
import com.android.systemui.common.ui.binder.IconViewBinder
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
import com.android.systemui.people.ui.view.PeopleViewBinder.bind
|
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.FooterActionsButtonViewModel
|
||||||
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel
|
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.FooterActionsSecurityButtonViewModel
|
||||||
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
|
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/** A ViewBinder for [FooterActionsViewBinder]. */
|
/** A ViewBinder for [FooterActionsViewBinder]. */
|
||||||
object FooterActionsViewBinder {
|
@SysUISingleton
|
||||||
|
class FooterActionsViewBinder @Inject constructor() {
|
||||||
/** Create a view that can later be [bound][bind] to a [FooterActionsViewModel]. */
|
/** Create a view that can later be [bound][bind] to a [FooterActionsViewModel]. */
|
||||||
@JvmStatic
|
|
||||||
fun create(context: Context): LinearLayout {
|
fun create(context: Context): LinearLayout {
|
||||||
return LayoutInflater.from(context).inflate(R.layout.footer_actions, /* root= */ null)
|
return LayoutInflater.from(context).inflate(R.layout.footer_actions, /* root= */ null)
|
||||||
as LinearLayout
|
as LinearLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Bind [view] to [viewModel]. */
|
/** Bind [view] to [viewModel]. */
|
||||||
@JvmStatic
|
|
||||||
fun bind(
|
fun bind(
|
||||||
view: LinearLayout,
|
view: LinearLayout,
|
||||||
viewModel: FooterActionsViewModel,
|
viewModel: FooterActionsViewModel,
|
||||||
@@ -98,6 +98,11 @@ object FooterActionsViewBinder {
|
|||||||
var previousForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
|
var previousForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
|
||||||
var previousUserSwitcher: FooterActionsButtonViewModel? = 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 {
|
view.repeatWhenAttached {
|
||||||
val attachedScope = this.lifecycleScope
|
val attachedScope = this.lifecycleScope
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
* the UI should still participate to the layout it is included in (i.e. in the View world it
|
||||||
* should be INVISIBLE, not GONE).
|
* should be INVISIBLE, not GONE).
|
||||||
*/
|
*/
|
||||||
private val _isVisible = MutableStateFlow(true)
|
private val _isVisible = MutableStateFlow(false)
|
||||||
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
|
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
|
||||||
|
|
||||||
/** The alpha the UI rendering this ViewModel should have. */
|
/** The alpha the UI rendering this ViewModel should have. */
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
@Mock private QSSquishinessController mSquishinessController;
|
@Mock private QSSquishinessController mSquishinessController;
|
||||||
@Mock private FooterActionsViewModel mFooterActionsViewModel;
|
@Mock private FooterActionsViewModel mFooterActionsViewModel;
|
||||||
@Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
|
@Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
|
||||||
|
@Mock private FooterActionsViewBinder mFooterActionsViewBinder;
|
||||||
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
|
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
|
||||||
@Mock private FeatureFlags mFeatureFlags;
|
@Mock private FeatureFlags mFeatureFlags;
|
||||||
private View mQsFragmentView;
|
private View mQsFragmentView;
|
||||||
@@ -558,6 +559,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
mock(QSLogger.class),
|
mock(QSLogger.class),
|
||||||
mock(FooterActionsController.class),
|
mock(FooterActionsController.class),
|
||||||
mFooterActionsViewModelFactory,
|
mFooterActionsViewModelFactory,
|
||||||
|
mFooterActionsViewBinder,
|
||||||
mLargeScreenShadeInterpolator,
|
mLargeScreenShadeInterpolator,
|
||||||
mFeatureFlags);
|
mFeatureFlags);
|
||||||
}
|
}
|
||||||
@@ -584,7 +586,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader);
|
when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader);
|
||||||
when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext));
|
when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext));
|
||||||
when(mQsFragmentView.findViewById(R.id.qs_footer_actions)).thenAnswer(
|
when(mQsFragmentView.findViewById(R.id.qs_footer_actions)).thenAnswer(
|
||||||
invocation -> FooterActionsViewBinder.create(mContext));
|
invocation -> new FooterActionsViewBinder().create(mContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpInflater() {
|
private void setUpInflater() {
|
||||||
|
|||||||
@@ -376,13 +376,13 @@ class FooterActionsViewModelTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun isVisible() {
|
fun isVisible() {
|
||||||
val underTest = utils.footerActionsViewModel()
|
val underTest = utils.footerActionsViewModel()
|
||||||
assertThat(underTest.isVisible.value).isTrue()
|
|
||||||
|
|
||||||
underTest.onVisibilityChangeRequested(visible = false)
|
|
||||||
assertThat(underTest.isVisible.value).isFalse()
|
assertThat(underTest.isVisible.value).isFalse()
|
||||||
|
|
||||||
underTest.onVisibilityChangeRequested(visible = true)
|
underTest.onVisibilityChangeRequested(visible = true)
|
||||||
assertThat(underTest.isVisible.value).isTrue()
|
assertThat(underTest.isVisible.value).isTrue()
|
||||||
|
|
||||||
|
underTest.onVisibilityChangeRequested(visible = false)
|
||||||
|
assertThat(underTest.isVisible.value).isFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user