Move MPPA and subclasses to subpackage 'profiles'

This will let us unpack these files a bit, move some inner classes out
and make a home for additional code to improve the patterns here.

Pure mechanical refactor.

Bug: n/a
Test: atest IntentResolver-tests-unit
Change-Id: I138313fc0e84b603b6f173a27cb3b96c91ecc194
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index cdc05b9..62b7999 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -138,8 +138,6 @@
 import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
 import com.android.intentresolver.shortcuts.AppPredictorFactory;
 import com.android.intentresolver.shortcuts.ShortcutLoader;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.ProfileType;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig;
 import com.android.intentresolver.v2.data.repository.DevicePolicyResources;
 import com.android.intentresolver.v2.emptystate.NoAppsAvailableEmptyStateProvider;
 import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider;
@@ -148,6 +146,12 @@
 import com.android.intentresolver.v2.platform.AppPredictionAvailable;
 import com.android.intentresolver.v2.platform.ImageEditor;
 import com.android.intentresolver.v2.platform.NearbyShare;
+import com.android.intentresolver.v2.profiles.ChooserMultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter.ProfileType;
+import com.android.intentresolver.v2.profiles.OnProfileSelectedListener;
+import com.android.intentresolver.v2.profiles.OnSwitchOnWorkSelectedListener;
+import com.android.intentresolver.v2.profiles.TabConfig;
 import com.android.intentresolver.v2.ui.ActionTitle;
 import com.android.intentresolver.v2.ui.ShareResultSender;
 import com.android.intentresolver.v2.ui.ShareResultSenderFactory;
@@ -245,7 +249,7 @@
     private ResolverActivity.PickTargetOptionRequest mPickOptionRequest;
 
     @Nullable
-    private MultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
+    private OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
 
     //////////////////////////////////////////////////////////////////////////////////////////////
     //////////////////////////////////////////////////////////////////////////////////////////////
@@ -1169,7 +1173,7 @@
                 R.layout.resolver_profile_tab_button,
                 com.android.internal.R.id.profile_pager,
                 () -> onProfileTabSelected(viewPager.getCurrentItem()),
-                new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+                new OnProfileSelectedListener() {
                     @Override
                     public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {}
 
diff --git a/java/src/com/android/intentresolver/v2/ResolverActivity.java b/java/src/com/android/intentresolver/v2/ResolverActivity.java
index 77d1dbf..2d26932 100644
--- a/java/src/com/android/intentresolver/v2/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/v2/ResolverActivity.java
@@ -100,15 +100,18 @@
 import com.android.intentresolver.icons.DefaultTargetDataLoader;
 import com.android.intentresolver.icons.TargetDataLoader;
 import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.ProfileType;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig;
 import com.android.intentresolver.v2.data.repository.DevicePolicyResources;
 import com.android.intentresolver.v2.domain.model.Profile;
 import com.android.intentresolver.v2.emptystate.NoAppsAvailableEmptyStateProvider;
 import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider;
 import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
 import com.android.intentresolver.v2.emptystate.WorkProfilePausedEmptyStateProvider;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.OnSwitchOnWorkSelectedListener;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter.ProfileType;
+import com.android.intentresolver.v2.profiles.OnProfileSelectedListener;
+import com.android.intentresolver.v2.profiles.TabConfig;
+import com.android.intentresolver.v2.profiles.ResolverMultiProfilePagerAdapter;
 import com.android.intentresolver.v2.ui.ActionTitle;
 import com.android.intentresolver.v2.ui.model.ActivityLaunch;
 import com.android.intentresolver.v2.ui.model.ResolverRequest;
@@ -1865,7 +1868,7 @@
                 R.layout.resolver_profile_tab_button,
                 com.android.internal.R.id.profile_pager,
                 () -> onProfileTabSelected(viewPager.getCurrentItem()),
-                new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+                new OnProfileSelectedListener() {
                     @Override
                     public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {
                         resetButtonBar();
diff --git a/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java b/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java
new file mode 100644
index 0000000..c5b3527
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.v2.profiles;
+
+/**
+ * Delegate to set up a given adapter and page view to be used together.
+ *
+ * @param <PageViewT>          (as in {@link MultiProfilePagerAdapter}).
+ * @param <SinglePageAdapterT> (as in {@link MultiProfilePagerAdapter}).
+ */
+public interface AdapterBinder<PageViewT, SinglePageAdapterT> {
+    /**
+     * The given {@code view} will be associated with the given {@code adapter}. Do any work
+     * necessary to configure them compatibly, introduce them to each other, etc.
+     */
+    void bind(PageViewT view, SinglePageAdapterT adapter);
+}
diff --git a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java
similarity index 98%
rename from java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java
rename to java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java
index 42eb077..0ee9d14 100644
--- a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
 
 import android.content.Context;
 import android.os.UserHandle;
diff --git a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java
similarity index 81%
rename from java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
rename to java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java
index 7940309..43785db 100644
--- a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -32,7 +32,6 @@
 import com.android.intentresolver.ResolverListAdapter;
 import com.android.intentresolver.emptystate.EmptyState;
 import com.android.intentresolver.emptystate.EmptyStateProvider;
-import com.android.intentresolver.v2.emptystate.EmptyStateUiHelper;
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.common.collect.ImmutableList;
@@ -48,20 +47,6 @@
 
 /**
  * Skeletal {@link PagerAdapter} implementation for a UI with per-profile tabs (as in Sharesheet).
- * <p>
- * TODO: attempt to further restrict visibility/improve encapsulation in the methods we expose.
- * <p>
- * TODO: deprecate and audit/fix usages of any methods that refer to the "active" or "inactive"
- * <p>
- * adapters; these were marked {@link VisibleForTesting} and their usage seems like an accident
- * waiting to happen since clients seem to make assumptions about which adapter will be "active" in
- * a particular context, and more explicit APIs would make sure those were valid.
- * <p>
- * TODO: consider renaming legacy methods (e.g. why do we know it's a "list", not just a "page"?)
- * <p>
- * TODO: this is part of an in-progress refactor to merge with `GenericMultiProfilePagerAdapter`.
- * As originally noted there, we've reduced explicit references to the `ResolverListAdapter` base
- * type and may be able to drop the type constraint.
  *
  * @param <PageViewT> the type of the widget that represents the contents of a page in this adapter
  * @param <SinglePageAdapterT> the type of a "root" adapter class to be instantiated and included in
@@ -71,24 +56,11 @@
  * be possible to get the list adapter from the page adapter via our
  * <code>mListAdapterExtractor</code>.
  */
-class MultiProfilePagerAdapter<
+public class MultiProfilePagerAdapter<
         PageViewT extends ViewGroup,
         SinglePageAdapterT,
         ListAdapterT extends ResolverListAdapter> extends PagerAdapter {
 
-    /**
-     * Delegate to set up a given adapter and page view to be used together.
-     * @param <PageViewT> (as in {@link MultiProfilePagerAdapter}).
-     * @param <SinglePageAdapterT> (as in {@link MultiProfilePagerAdapter}).
-     */
-    public interface AdapterBinder<PageViewT, SinglePageAdapterT> {
-        /**
-         * The given {@code view} will be associated with the given {@code adapter}. Do any work
-         * necessary to configure them compatibly, introduce them to each other, etc.
-         */
-        void bind(PageViewT view, SinglePageAdapterT adapter);
-    }
-
     public static final int PROFILE_PERSONAL = 0;
     public static final int PROFILE_WORK = 1;
 
@@ -110,27 +82,6 @@
     private int mCurrentPage;
     private OnProfileSelectedListener mOnProfileSelectedListener;
 
-    public static class TabConfig<PageAdapterT> {
-        private final @ProfileType int mProfile;
-        private final String mTabLabel;
-        private final String mTabAccessibilityLabel;
-        private final String mTabTag;
-        private final PageAdapterT mPageAdapter;
-
-        public TabConfig(
-                @ProfileType int profile,
-                String tabLabel,
-                String tabAccessibilityLabel,
-                String tabTag,
-                PageAdapterT pageAdapter) {
-            mProfile = profile;
-            mTabLabel = tabLabel;
-            mTabAccessibilityLabel = tabAccessibilityLabel;
-            mTabTag = tabTag;
-            mPageAdapter = pageAdapter;
-        }
-    }
-
     protected MultiProfilePagerAdapter(
             Function<SinglePageAdapterT, ListAdapterT> listAdapterExtractor,
             AdapterBinder<PageViewT, SinglePageAdapterT> adapterBinder,
@@ -291,7 +242,7 @@
             int tabButtonLayoutResId,
             int tabPageContentViewId,
             Runnable onTabChangeListener,
-            MultiProfilePagerAdapter.OnProfileSelectedListener clientOnProfileSelectedListener) {
+            OnProfileSelectedListener clientOnProfileSelectedListener) {
         tabHost.setup();
         viewPager.setSaveEnabled(false);
 
@@ -325,7 +276,7 @@
         viewPager.setVisibility(View.VISIBLE);
         tabHost.setCurrentTab(getCurrentPage());
         mOnProfileSelectedListener =
-                new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+                new OnProfileSelectedListener() {
                     @Override
                     public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {
                         tabHost.setCurrentTab(pageNumber);
@@ -457,7 +408,7 @@
     }
 
     public final PageViewT getListViewForIndex(int index) {
-        return getItem(index).mView;
+        return getItem(index).getView();
     }
 
     /**
@@ -471,7 +422,7 @@
         if (!hasPageForIndex(index)) {
             return null;
         }
-        return getItem(index).mAdapter;
+        return getItem(index).getAdapter();
     }
 
     /**
@@ -692,18 +643,6 @@
         showEmptyState(listAdapter, emptyState, clickListener);
     }
 
-    /**
-     * Class to get user id of the current process
-     */
-    public static class MyUserIdProvider {
-        /**
-         * @return user id of the current process
-         */
-        public int getMyUserId() {
-            return UserHandle.myUserId();
-        }
-    }
-
     private void showEmptyState(
             ListAdapterT activeListAdapter,
             EmptyState emptyState,
@@ -750,86 +689,4 @@
                     && mWorkProfileQuietModeChecker.get());
     }
 
-    // TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
-    // should be the owner of all per-profile data (especially now that the API is generic)?
-    private static class ProfileDescriptor<PageViewT, SinglePageAdapterT> {
-        final @ProfileType int mProfile;
-        final String mTabLabel;
-        final String mTabAccessibilityLabel;
-        final String mTabTag;
-
-        final ViewGroup mRootView;
-        final EmptyStateUiHelper mEmptyStateUi;
-
-        // TODO: post-refactoring, we may not need to retain these ivars directly (since they may
-        // be encapsulated within the `EmptyStateUiHelper`?).
-        private final ViewGroup mEmptyStateView;
-
-        private final SinglePageAdapterT mAdapter;
-        private final PageViewT mView;
-
-        ProfileDescriptor(
-                @ProfileType int forProfile,
-                String tabLabel,
-                String tabAccessibilityLabel,
-                String tabTag,
-                ViewGroup rootView,
-                SinglePageAdapterT adapter,
-                Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
-            mProfile = forProfile;
-            mTabLabel = tabLabel;
-            mTabAccessibilityLabel = tabAccessibilityLabel;
-            mTabTag = tabTag;
-            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,
-                    com.android.internal.R.id.resolver_list,
-                    containerBottomPaddingOverrideSupplier);
-        }
-
-        protected ViewGroup getEmptyStateView() {
-            return mEmptyStateView;
-        }
-
-        private void setupContainerPadding() {
-            mEmptyStateUi.setupContainerPadding();
-        }
-    }
-
-    /** Listener interface for changes between the per-profile UI tabs. */
-    public interface OnProfileSelectedListener {
-        /**
-         * Callback for when the user changes the active tab.
-         * <p>This callback is only called when the intent resolver or share sheet shows
-         * more than one profile.
-         * @param profileId the ID of the newly-selected profile, e.g. {@link #PROFILE_PERSONAL}
-         * if the personal profile tab was selected or {@link #PROFILE_WORK} if the work profile tab
-         * was selected.
-         */
-        void onProfilePageSelected(@ProfileType int profileId, int pageNumber);
-
-
-        /**
-         * Callback for when the scroll state changes. Useful for discovering when the user begins
-         * dragging, when the pager is automatically settling to the current page, or when it is
-         * fully stopped/idle.
-         * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
-         *              or {@link ViewPager#SCROLL_STATE_SETTLING}
-         * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
-         */
-        void onProfilePageStateChanged(int state);
-    }
-
-    /**
-     * Listener for when the user switches on the work profile from the work tab.
-     */
-    public interface OnSwitchOnWorkSelectedListener {
-        /**
-         * Callback for when the user switches on the work profile from the work tab.
-         */
-        void onSwitchOnWorkSelected();
-    }
 }
diff --git a/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java b/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java
new file mode 100644
index 0000000..7bdbec4
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.v2.profiles;
+
+import androidx.viewpager.widget.ViewPager;
+
+/** Listener interface for changes between the per-profile UI tabs. */
+public interface OnProfileSelectedListener {
+    /**
+     * Callback for when the user changes the active tab.
+     * <p>This callback is only called when the intent resolver or share sheet shows
+     * more than one profile.
+     *
+     * @param profileId the ID of the newly-selected profile, e.g. {@link #PROFILE_PERSONAL}
+     *                  if the personal profile tab was selected or {@link #PROFILE_WORK} if the
+     *                  work profile tab
+     *                  was selected.
+     */
+    void onProfilePageSelected(@MultiProfilePagerAdapter.ProfileType int profileId, int pageNumber);
+
+
+    /**
+     * Callback for when the scroll state changes. Useful for discovering when the user begins
+     * dragging, when the pager is automatically settling to the current page, or when it is
+     * fully stopped/idle.
+     *
+     * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+     *              or {@link ViewPager#SCROLL_STATE_SETTLING}
+     * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+     */
+    void onProfilePageStateChanged(int state);
+}
diff --git a/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java b/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java
new file mode 100644
index 0000000..3dbbd4d
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.v2.profiles;
+
+/**
+ * Listener for when the user switches on the work profile from the work tab.
+ */
+public interface OnSwitchOnWorkSelectedListener {
+    /**
+     * Callback for when the user switches on the work profile from the work tab.
+     */
+    void onSwitchOnWorkSelected();
+}
diff --git a/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java b/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java
new file mode 100644
index 0000000..e2e9c19
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.v2.profiles;
+
+import android.view.ViewGroup;
+
+import com.android.intentresolver.v2.emptystate.EmptyStateUiHelper;
+
+import java.util.Optional;
+import java.util.function.Supplier;
+
+// TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
+// should be the owner of all per-profile data (especially now that the API is generic)?
+class ProfileDescriptor<PageViewT, SinglePageAdapterT> {
+    final @MultiProfilePagerAdapter.ProfileType int mProfile;
+    final String mTabLabel;
+    final String mTabAccessibilityLabel;
+    final String mTabTag;
+
+    final ViewGroup mRootView;
+    final EmptyStateUiHelper mEmptyStateUi;
+
+    // TODO: post-refactoring, we may not need to retain these ivars directly (since they may
+    // be encapsulated within the `EmptyStateUiHelper`?).
+    private final ViewGroup mEmptyStateView;
+
+    private final SinglePageAdapterT mAdapter;
+
+    public SinglePageAdapterT getAdapter() {
+        return mAdapter;
+    }
+
+    public PageViewT getView() {
+        return mView;
+    }
+
+    private final PageViewT mView;
+
+    ProfileDescriptor(
+            @MultiProfilePagerAdapter.ProfileType int forProfile,
+            String tabLabel,
+            String tabAccessibilityLabel,
+            String tabTag,
+            ViewGroup rootView,
+            SinglePageAdapterT adapter,
+            Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
+        mProfile = forProfile;
+        mTabLabel = tabLabel;
+        mTabAccessibilityLabel = tabAccessibilityLabel;
+        mTabTag = tabTag;
+        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,
+                com.android.internal.R.id.resolver_list,
+                containerBottomPaddingOverrideSupplier);
+    }
+
+    protected ViewGroup getEmptyStateView() {
+        return mEmptyStateView;
+    }
+
+    public void setupContainerPadding() {
+        mEmptyStateUi.setupContainerPadding();
+    }
+}
diff --git a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java
similarity index 97%
rename from java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java
rename to java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java
index c2e1ae0..e44cf8d 100644
--- a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
 
 import android.content.Context;
 import android.os.UserHandle;
diff --git a/java/src/com/android/intentresolver/v2/profiles/TabConfig.java b/java/src/com/android/intentresolver/v2/profiles/TabConfig.java
new file mode 100644
index 0000000..994f8af
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/TabConfig.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.v2.profiles;
+
+public class TabConfig<PageAdapterT> {
+    final @MultiProfilePagerAdapter.ProfileType int mProfile;
+    final String mTabLabel;
+    final String mTabAccessibilityLabel;
+    final String mTabTag;
+    final PageAdapterT mPageAdapter;
+
+    public TabConfig(
+            @MultiProfilePagerAdapter.ProfileType int profile,
+            String tabLabel,
+            String tabAccessibilityLabel,
+            String tabTag,
+            PageAdapterT pageAdapter) {
+        mProfile = profile;
+        mTabLabel = tabLabel;
+        mTabAccessibilityLabel = tabAccessibilityLabel;
+        mTabTag = tabTag;
+        mPageAdapter = pageAdapter;
+    }
+}
diff --git a/tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt b/tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt
similarity index 98%
rename from tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt
rename to tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt
index 8e5f00a..5b6b5d9 100644
--- a/tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.intentresolver.v2
+package com.android.intentresolver.v2.profiles
 
 import android.os.UserHandle
 import android.view.LayoutInflater
@@ -28,7 +28,6 @@
 import com.android.intentresolver.ResolverListAdapter
 import com.android.intentresolver.emptystate.EmptyStateProvider
 import com.android.intentresolver.mock
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig
 import com.android.intentresolver.whenever
 import com.google.common.collect.ImmutableList
 import com.google.common.truth.Truth.assertThat