diff options
| author | 2023-10-05 17:16:40 +0000 | |
|---|---|---|
| committer | 2023-10-05 18:34:35 +0000 | |
| commit | c2f1d0cc70ef6083fd47e055a421fd74f620ea33 (patch) | |
| tree | 7fd772af3eaa95e2c561fc3405baab2d527d1c56 /java | |
| parent | 989de76169699beee2c92a8ce41bc636896a66b6 (diff) | |
"Bottom padding overrides" -> EmptyStateUiHelper
As part of ongoing work to pull low-level empty state responsibilities
out of the pager adapter, this CL generally replicates the change
prototyped in ag/24516421/4..5, in smaller incremental steps to "show
the work." As originally described in that CL:
"... moves ownership/usage of the 'container bottom padding
override supplier' over to the UI helper; this PagerAdapter dependency
is really only used in empty-state logic, so it can be handed over to
the extracted component *instead of* retaining it as an ivar in the
PagerAdapter."
As presented in this CL, the "incremental steps" per-snapshot are:
1. Move `getActiveEmptyStateView()` from `ChooserActivity` to
`MultiProfilePagerAdapter`, and expose it in favor of the broader
`getEmptyStateView()` method that `ChooserActivity` previously
used to implement the lower-level logic.
2. Remove `MultiProfilePagerAdapter.setupContainerPadding()`
parameters since they're just derived from a combination of a
single hard-coded (resource) symbol, and a concern that already
belonged to the pager-adapter (`getActiveEmptyStateView()`).
Switch tests to using one of our real layouts so that we can find
an empty-state container with the expected View ID.
Also update method visibility to show `setupContainerPadding()`
isn't intended to be overridden in the more-modern "generic pager"
design, and update Javadoc accordingly.
3. Inline `ChooserMultiProfilePagerAdapter.setupContainerPadding()`
as part of its `setEmptyStateBottomOffset()`, since the latter
method is never called anywhere else (and both concerns already
belonged to the specialized pager-adapter).
4. Refactor the internal `setupContainerPadding()` to operate on
profile descriptors instead of container Views. This is based on
the observation that both callers of `setupContainerPadding()`
were passing containers that they had to query from the
descriptor's empty-state view anyways, and the lookup used the
same View ID in both cases. This change encapsulates those shared
concerns at a higher level of abstraction.
5. Move the implementation logic of `setupContainerPadding()` into
the descriptor inner-class; given the override-supplier, the rest
of the operation can be implemented just using the info available
to the descriptor.
6. Move ownership of the override-supplier into the descriptor (to be
shared among all descriptor instances). The outer pager-adapter
had no remaining need to reference the supplier, and we can easily
confirm that this results in `setupContainerPadding()` calls for
each descriptor instance using the same supplier instance they
would've used before.
7. Moves implementation logic (including [shared] ownership of the
override-supplier) from the descriptor down to the empty-state
helper which now encapsulates the entire `setupContainerPadding()`
operation with zero args.
This may require *slightly* more of a leap-of-faith than the other
"steps," but note the extensive test coverage: the existing
`MultiProfilePagerAdapterTest` covers this exact functionality
as integrated into a broader config; parallel unit tests are
newly-added in `EmptyStateUiHelper`; and even our "broad-scope"
integration tests exercise empty-state logic to _some_ degree.
8. Inlines some client usages to simplify scaffolding that we don't
really need after the earlier refactoring changes.
Bug: 302311217
Test: IntentResolverUnitTests
Change-Id: Icc460ede5b8a0314d5c807dd884e6e2b7044bee9
Diffstat (limited to 'java')
6 files changed, 110 insertions, 54 deletions
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java index a755b9e9..9a8b0e2a 100644 --- a/java/src/com/android/intentresolver/v2/ChooserActivity.java +++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java @@ -1473,7 +1473,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements rowsToShow--; } } else { - ViewGroup currentEmptyStateView = getActiveEmptyStateView(); + ViewGroup currentEmptyStateView = + mChooserMultiProfilePagerAdapter.getActiveEmptyStateView(); if (currentEmptyStateView.getVisibility() == View.VISIBLE) { offset += currentEmptyStateView.getHeight(); } @@ -1507,11 +1508,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements return PROFILE_PERSONAL; } - private ViewGroup getActiveEmptyStateView() { - int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage(); - return mChooserMultiProfilePagerAdapter.getEmptyStateView(currentPage); - } - @Override // ResolverListCommunicator public void onHandlePackagesChanged(ResolverListAdapter listAdapter) { mChooserMultiProfilePagerAdapter.getActiveListAdapter().notifyDataSetChanged(); @@ -1782,8 +1778,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements if (shouldShowTabs()) { mChooserMultiProfilePagerAdapter .setEmptyStateBottomOffset(insets.getSystemWindowInsetBottom()); - mChooserMultiProfilePagerAdapter.setupContainerPadding( - getActiveEmptyStateView().findViewById(com.android.internal.R.id.resolver_empty_state_container)); } WindowInsets result = super.onApplyWindowInsets(v, insets); diff --git a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java index d3c9efea..8ca976bc 100644 --- a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java +++ b/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java @@ -128,6 +128,7 @@ public class ChooserMultiProfilePagerAdapter extends MultiProfilePagerAdapter< public void setEmptyStateBottomOffset(int bottomOffset) { mBottomPaddingOverrideSupplier.setEmptyStateBottomOffset(bottomOffset); + setupContainerPadding(); } /** diff --git a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java index b2a167e1..ad9614b9 100644 --- a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java +++ b/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java @@ -89,7 +89,6 @@ public class MultiProfilePagerAdapter< private final Function<SinglePageAdapterT, ListAdapterT> mListAdapterExtractor; private final AdapterBinder<PageViewT, SinglePageAdapterT> mAdapterBinder; private final Supplier<ViewGroup> mPageViewInflater; - private final Supplier<Optional<Integer>> mContainerBottomPaddingOverrideSupplier; private final ImmutableList<ProfileDescriptor<PageViewT, SinglePageAdapterT>> mItems; @@ -123,19 +122,20 @@ public class MultiProfilePagerAdapter< mListAdapterExtractor = listAdapterExtractor; mAdapterBinder = adapterBinder; mPageViewInflater = pageViewInflater; - mContainerBottomPaddingOverrideSupplier = containerBottomPaddingOverrideSupplier; ImmutableList.Builder<ProfileDescriptor<PageViewT, SinglePageAdapterT>> items = new ImmutableList.Builder<>(); for (SinglePageAdapterT adapter : adapters) { - items.add(createProfileDescriptor(adapter)); + items.add(createProfileDescriptor(adapter, containerBottomPaddingOverrideSupplier)); } mItems = items.build(); } private ProfileDescriptor<PageViewT, SinglePageAdapterT> createProfileDescriptor( - SinglePageAdapterT adapter) { - return new ProfileDescriptor<>(mPageViewInflater.get(), adapter); + SinglePageAdapterT adapter, + Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { + return new ProfileDescriptor<>( + mPageViewInflater.get(), adapter, containerBottomPaddingOverrideSupplier); } public void setOnProfileSelectedListener(OnProfileSelectedListener listener) { @@ -235,10 +235,14 @@ public class MultiProfilePagerAdapter< return mItems.get(pageIndex); } - public ViewGroup getEmptyStateView(int pageIndex) { + private ViewGroup getEmptyStateView(int pageIndex) { return getItem(pageIndex).getEmptyStateView(); } + public ViewGroup getActiveEmptyStateView() { + return getEmptyStateView(getCurrentPage()); + } + /** * Returns the number of {@link ProfileDescriptor} objects. * <p>For a normal consumer device with only one user returns <code>1</code>. @@ -454,12 +458,10 @@ public class MultiProfilePagerAdapter< descriptor.mRootView.findViewById( com.android.internal.R.id.resolver_list).setVisibility(View.GONE); descriptor.mEmptyStateUi.resetViewVisibilities(); + descriptor.setupContainerPadding(); ViewGroup emptyStateView = descriptor.getEmptyStateView(); - View container = emptyStateView.findViewById( - com.android.internal.R.id.resolver_empty_state_container); - setupContainerPadding(container); TextView titleView = emptyStateView.findViewById( com.android.internal.R.id.resolver_empty_state_title); @@ -493,17 +495,11 @@ public class MultiProfilePagerAdapter< } /** - * Sets up the padding of the view containing the empty state screens. - * <p>This method is meant to be overridden so that subclasses can customize the padding. + * Sets up the padding of the view containing the empty state screens for the current adapter + * view. */ - public void setupContainerPadding(View container) { - Optional<Integer> bottomPaddingOverride = mContainerBottomPaddingOverrideSupplier.get(); - bottomPaddingOverride.ifPresent(paddingBottom -> - container.setPadding( - container.getPaddingLeft(), - container.getPaddingTop(), - container.getPaddingRight(), - paddingBottom)); + protected final void setupContainerPadding() { + getItem(getCurrentPage()).setupContainerPadding(); } public void showListView(ListAdapterT activeListAdapter) { @@ -534,17 +530,25 @@ public class MultiProfilePagerAdapter< private final SinglePageAdapterT mAdapter; private final PageViewT mView; - ProfileDescriptor(ViewGroup rootView, SinglePageAdapterT adapter) { + ProfileDescriptor( + ViewGroup rootView, + SinglePageAdapterT adapter, + Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { mRootView = rootView; mAdapter = adapter; mEmptyStateView = rootView.findViewById(com.android.internal.R.id.resolver_empty_state); mView = (PageViewT) rootView.findViewById(com.android.internal.R.id.resolver_list); - mEmptyStateUi = new EmptyStateUiHelper(rootView); + mEmptyStateUi = + new EmptyStateUiHelper(rootView, containerBottomPaddingOverrideSupplier); } protected ViewGroup getEmptyStateView() { return mEmptyStateView; } + + private void setupContainerPadding() { + mEmptyStateUi.setupContainerPadding(); + } } /** Listener interface for changes between the per-profile UI tabs. */ diff --git a/java/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelper.java b/java/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelper.java index 7230b042..fc852f5c 100644 --- a/java/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelper.java +++ b/java/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelper.java @@ -18,16 +18,36 @@ package com.android.intentresolver.v2.emptystate; import android.view.View; import android.view.ViewGroup; +import java.util.Optional; +import java.util.function.Supplier; + /** * Helper for building `MultiProfilePagerAdapter` tab UIs for profile tabs that are "blocked" by * some empty-state status. */ public class EmptyStateUiHelper { private final View mEmptyStateView; + private final Supplier<Optional<Integer>> mContainerBottomPaddingOverrideSupplier; - public EmptyStateUiHelper(ViewGroup rootView) { + public EmptyStateUiHelper( + ViewGroup rootView, + Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) { mEmptyStateView = rootView.requireViewById(com.android.internal.R.id.resolver_empty_state); + mContainerBottomPaddingOverrideSupplier = containerBottomPaddingOverrideSupplier; + } + + /** Sets up the padding of the view containing the empty state screens. */ + public void setupContainerPadding() { + View container = mEmptyStateView.requireViewById( + com.android.internal.R.id.resolver_empty_state_container); + Optional<Integer> bottomPaddingOverride = mContainerBottomPaddingOverrideSupplier.get(); + bottomPaddingOverride.ifPresent(paddingBottom -> + container.setPadding( + container.getPaddingLeft(), + container.getPaddingTop(), + container.getPaddingRight(), + paddingBottom)); } public void resetViewVisibilities() { diff --git a/java/tests/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt b/java/tests/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt index f1af9790..f5dc0935 100644 --- a/java/tests/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt +++ b/java/tests/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt @@ -26,7 +26,6 @@ import com.android.intentresolver.MultiProfilePagerAdapter.PROFILE_PERSONAL import com.android.intentresolver.MultiProfilePagerAdapter.PROFILE_WORK import com.android.intentresolver.R import com.android.intentresolver.ResolverListAdapter -import com.android.intentresolver.any import com.android.intentresolver.emptystate.EmptyStateProvider import com.android.intentresolver.mock import com.android.intentresolver.whenever @@ -35,8 +34,6 @@ import com.google.common.truth.Truth.assertThat import java.util.Optional import java.util.function.Supplier import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify class MultiProfilePagerAdapterTest { private val PERSONAL_USER_HANDLE = UserHandle.of(10) @@ -158,20 +155,15 @@ class MultiProfilePagerAdapterTest { @Test fun testBottomPaddingDelegate_default() { - val container = - mock<View> { - whenever(getPaddingLeft()).thenReturn(1) - whenever(getPaddingTop()).thenReturn(2) - whenever(getPaddingRight()).thenReturn(3) - whenever(getPaddingBottom()).thenReturn(4) - } + val personalListAdapter = + mock<ResolverListAdapter> { whenever(getUserHandle()).thenReturn(PERSONAL_USER_HANDLE) } val pagerAdapter = MultiProfilePagerAdapter( { listAdapter: ResolverListAdapter -> listAdapter }, { listView: ListView, bindAdapter: ResolverListAdapter -> listView.setAdapter(bindAdapter) }, - ImmutableList.of(), + ImmutableList.of(personalListAdapter), object : EmptyStateProvider {}, { false }, PROFILE_PERSONAL, @@ -180,26 +172,29 @@ class MultiProfilePagerAdapterTest { inflater, { Optional.empty() } ) - pagerAdapter.setupContainerPadding(container) - verify(container, never()).setPadding(any(), any(), any(), any()) + val container = + pagerAdapter + .getActiveEmptyStateView() + .requireViewById<View>(com.android.internal.R.id.resolver_empty_state_container) + container.setPadding(1, 2, 3, 4) + pagerAdapter.setupContainerPadding() + assertThat(container.paddingLeft).isEqualTo(1) + assertThat(container.paddingTop).isEqualTo(2) + assertThat(container.paddingRight).isEqualTo(3) + assertThat(container.paddingBottom).isEqualTo(4) } @Test fun testBottomPaddingDelegate_override() { - val container = - mock<View> { - whenever(getPaddingLeft()).thenReturn(1) - whenever(getPaddingTop()).thenReturn(2) - whenever(getPaddingRight()).thenReturn(3) - whenever(getPaddingBottom()).thenReturn(4) - } + val personalListAdapter = + mock<ResolverListAdapter> { whenever(getUserHandle()).thenReturn(PERSONAL_USER_HANDLE) } val pagerAdapter = MultiProfilePagerAdapter( { listAdapter: ResolverListAdapter -> listAdapter }, { listView: ListView, bindAdapter: ResolverListAdapter -> listView.setAdapter(bindAdapter) }, - ImmutableList.of(), + ImmutableList.of(personalListAdapter), object : EmptyStateProvider {}, { false }, PROFILE_PERSONAL, @@ -208,8 +203,16 @@ class MultiProfilePagerAdapterTest { inflater, { Optional.of(42) } ) - pagerAdapter.setupContainerPadding(container) - verify(container).setPadding(1, 2, 3, 42) + val container = + pagerAdapter + .getActiveEmptyStateView() + .requireViewById<View>(com.android.internal.R.id.resolver_empty_state_container) + container.setPadding(1, 2, 3, 4) + pagerAdapter.setupContainerPadding() + assertThat(container.paddingLeft).isEqualTo(1) + assertThat(container.paddingTop).isEqualTo(2) + assertThat(container.paddingRight).isEqualTo(3) + assertThat(container.paddingBottom).isEqualTo(42) } @Test diff --git a/java/tests/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelperTest.kt b/java/tests/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelperTest.kt index 12943cd7..27ed7e38 100644 --- a/java/tests/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelperTest.kt +++ b/java/tests/src/com/android/intentresolver/v2/emptystate/EmptyStateUiHelperTest.kt @@ -22,12 +22,20 @@ import android.view.ViewGroup import android.widget.FrameLayout import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat +import java.util.Optional +import java.util.function.Supplier import org.junit.Before import org.junit.Test class EmptyStateUiHelperTest { private val context = InstrumentationRegistry.getInstrumentation().getContext() + var shouldOverrideContainerPadding = false + val containerPaddingSupplier = + Supplier<Optional<Int>> { + Optional.ofNullable(if (shouldOverrideContainerPadding) 42 else null) + } + lateinit var rootContainer: ViewGroup lateinit var emptyStateTitleView: View lateinit var emptyStateSubtitleView: View @@ -60,7 +68,7 @@ class EmptyStateUiHelperTest { emptyStateDefaultTextView = rootContainer.requireViewById(com.android.internal.R.id.empty) emptyStateContainerView = rootContainer.requireViewById(com.android.internal.R.id.resolver_empty_state_container) - emptyStateUiHelper = EmptyStateUiHelper(rootContainer) + emptyStateUiHelper = EmptyStateUiHelper(rootContainer, containerPaddingSupplier) } @Test @@ -109,4 +117,30 @@ class EmptyStateUiHelperTest { assertThat(emptyStateRootView.visibility).isEqualTo(View.GONE) } + + @Test + fun testBottomPaddingDelegate_default() { + shouldOverrideContainerPadding = false + emptyStateContainerView.setPadding(1, 2, 3, 4) + + emptyStateUiHelper.setupContainerPadding() + + assertThat(emptyStateContainerView.paddingLeft).isEqualTo(1) + assertThat(emptyStateContainerView.paddingTop).isEqualTo(2) + assertThat(emptyStateContainerView.paddingRight).isEqualTo(3) + assertThat(emptyStateContainerView.paddingBottom).isEqualTo(4) + } + + @Test + fun testBottomPaddingDelegate_override() { + shouldOverrideContainerPadding = true // Set bottom padding to 42. + emptyStateContainerView.setPadding(1, 2, 3, 4) + + emptyStateUiHelper.setupContainerPadding() + + assertThat(emptyStateContainerView.paddingLeft).isEqualTo(1) + assertThat(emptyStateContainerView.paddingTop).isEqualTo(2) + assertThat(emptyStateContainerView.paddingRight).isEqualTo(3) + assertThat(emptyStateContainerView.paddingBottom).isEqualTo(42) + } } |