From c2f1d0cc70ef6083fd47e055a421fd74f620ea33 Mon Sep 17 00:00:00 2001 From: Joshua Trask Date: Thu, 5 Oct 2023 17:16:40 +0000 Subject: "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 --- .../android/intentresolver/v2/ChooserActivity.java | 10 +---- .../v2/ChooserMultiProfilePagerAdapter.java | 1 + .../v2/MultiProfilePagerAdapter.java | 46 ++++++++++++---------- .../v2/emptystate/EmptyStateUiHelper.java | 22 ++++++++++- 4 files changed, 49 insertions(+), 30 deletions(-) (limited to 'java/src/com') 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 mListAdapterExtractor; private final AdapterBinder mAdapterBinder; private final Supplier mPageViewInflater; - private final Supplier> mContainerBottomPaddingOverrideSupplier; private final ImmutableList> mItems; @@ -123,19 +122,20 @@ public class MultiProfilePagerAdapter< mListAdapterExtractor = listAdapterExtractor; mAdapterBinder = adapterBinder; mPageViewInflater = pageViewInflater; - mContainerBottomPaddingOverrideSupplier = containerBottomPaddingOverrideSupplier; ImmutableList.Builder> items = new ImmutableList.Builder<>(); for (SinglePageAdapterT adapter : adapters) { - items.add(createProfileDescriptor(adapter)); + items.add(createProfileDescriptor(adapter, containerBottomPaddingOverrideSupplier)); } mItems = items.build(); } private ProfileDescriptor createProfileDescriptor( - SinglePageAdapterT adapter) { - return new ProfileDescriptor<>(mPageViewInflater.get(), adapter); + SinglePageAdapterT adapter, + Supplier> 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. *

For a normal consumer device with only one user returns 1. @@ -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. - *

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 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> 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> mContainerBottomPaddingOverrideSupplier; - public EmptyStateUiHelper(ViewGroup rootView) { + public EmptyStateUiHelper( + ViewGroup rootView, + Supplier> 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 bottomPaddingOverride = mContainerBottomPaddingOverrideSupplier.get(); + bottomPaddingOverride.ifPresent(paddingBottom -> + container.setPadding( + container.getPaddingLeft(), + container.getPaddingTop(), + container.getPaddingRight(), + paddingBottom)); } public void resetViewVisibilities() { -- cgit v1.2.3-59-g8ed1b