diff options
16 files changed, 358 insertions, 115 deletions
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java index 08022e983892..b2aa0431251d 100644 --- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -26,7 +26,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; /** * Skeletal {@link PagerAdapter} implementation of a work or personal profile page for @@ -34,6 +36,7 @@ import java.util.Objects; */ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { + private static final String TAG = "AbstractMultiProfilePagerAdapter"; static final int PROFILE_PERSONAL = 0; static final int PROFILE_WORK = 1; @IntDef({PROFILE_PERSONAL, PROFILE_WORK}) @@ -41,10 +44,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { private final Context mContext; private int mCurrentPage; + private OnProfileSelectedListener mOnProfileSelectedListener; + private Set<Integer> mLoadedPages; AbstractMultiProfilePagerAdapter(Context context, int currentPage) { mContext = Objects.requireNonNull(context); mCurrentPage = currentPage; + mLoadedPages = new HashSet<>(); + } + + void setOnProfileSelectedListener(OnProfileSelectedListener listener) { + mOnProfileSelectedListener = listener; } Context getContext() { @@ -57,15 +67,22 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { * page and rebuilds the list. */ void setupViewPager(ViewPager viewPager) { - viewPager.setCurrentItem(mCurrentPage); viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { mCurrentPage = position; - getActiveListAdapter().rebuildList(); + if (!mLoadedPages.contains(position)) { + getActiveListAdapter().rebuildList(); + mLoadedPages.add(position); + } + if (mOnProfileSelectedListener != null) { + mOnProfileSelectedListener.onProfileSelected(position); + } } }); viewPager.setAdapter(this); + viewPager.setCurrentItem(mCurrentPage); + mLoadedPages.add(mCurrentPage); } @Override @@ -90,7 +107,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { return mCurrentPage; } - UserHandle getCurrentUserHandle() { + @VisibleForTesting + public UserHandle getCurrentUserHandle() { return getActiveListAdapter().mResolverListController.getUserHandle(); } @@ -135,7 +153,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { * <p>This method is meant to be implemented with an implementation-specific return type * depending on the adapter type. */ - abstract Object getAdapterForIndex(int pageIndex); + @VisibleForTesting + public abstract Object getAdapterForIndex(int pageIndex); @VisibleForTesting public abstract ResolverListAdapter getActiveListAdapter(); @@ -152,7 +171,9 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { abstract Object getCurrentRootAdapter(); - abstract ViewGroup getCurrentAdapterView(); + abstract ViewGroup getActiveAdapterView(); + + abstract @Nullable ViewGroup getInactiveAdapterView(); protected class ProfileDescriptor { final ViewGroup rootView; @@ -160,4 +181,15 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { this.rootView = rootView; } } + + public interface OnProfileSelectedListener { + /** + * Callback for when the user changes the active tab from personal to work or vice versa. + * <p>This callback is only called when the intent resolver or share sheet shows + * the work and personal profiles. + * @param profileIndex {@link #PROFILE_PERSONAL} if the personal profile was selected or + * {@link #PROFILE_WORK} if the work profile was selected. + */ + void onProfileSelected(int profileIndex); + } }
\ No newline at end of file diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 9532faecb4df..8bbc343fa4ca 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -508,7 +508,6 @@ public class ChooserActivity extends ResolverActivity implements protected void onCreate(Bundle savedInstanceState) { final long intentReceivedTime = System.currentTimeMillis(); // This is the only place this value is being set. Effectively final. - //TODO(arangelov) - should there be a mIsAppPredictorComponentAvailable flag for work tab? mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable(); mIsSuccessfullySelected = false; @@ -689,29 +688,6 @@ public class ChooserActivity extends ResolverActivity implements mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll); } - final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header); - final float defaultElevation = chooserHeader.getElevation(); - final float chooserHeaderScrollElevation = - getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation); - - mChooserMultiProfilePagerAdapter.getCurrentAdapterView().addOnScrollListener( - new RecyclerView.OnScrollListener() { - public void onScrollStateChanged(RecyclerView view, int scrollState) { - } - - public void onScrolled(RecyclerView view, int dx, int dy) { - if (view.getChildCount() > 0) { - View child = view.getLayoutManager().findViewByPosition(0); - if (child == null || child.getTop() < 0) { - chooserHeader.setElevation(chooserHeaderScrollElevation); - return; - } - } - - chooserHeader.setElevation(defaultElevation); - } - }); - mResolverDrawerLayout.setOnCollapsedChangedListener( new ResolverDrawerLayout.OnCollapsedChangedListener() { @@ -1330,8 +1306,8 @@ public class ChooserActivity extends ResolverActivity implements } @Override - public void onPrepareAdapterView(ResolverListAdapter adapter) { - mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE); + public void addUseDifferentAppLabelIfNecessary(ResolverListAdapter adapter) { + mChooserMultiProfilePagerAdapter.getActiveAdapterView().setVisibility(View.VISIBLE); if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) { mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults( /* origTarget */ null, @@ -2202,7 +2178,7 @@ public class ChooserActivity extends ResolverActivity implements if (mChooserMultiProfilePagerAdapter == null) { return; } - RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getCurrentAdapterView(); + RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getActiveAdapterView(); ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter(); if (gridAdapter == null || recyclerView == null) { return; @@ -2328,6 +2304,8 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onListRebuilt(ResolverListAdapter listAdapter) { + setupScrollListener(); + ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter; if (chooserListAdapter.mDisplayList == null || chooserListAdapter.mDisplayList.isEmpty()) { @@ -2368,6 +2346,34 @@ public class ChooserActivity extends ResolverActivity implements } } + private void setupScrollListener() { + if (mResolverDrawerLayout == null) { + return; + } + final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header); + final float defaultElevation = chooserHeader.getElevation(); + final float chooserHeaderScrollElevation = + getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation); + + mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener( + new RecyclerView.OnScrollListener() { + public void onScrollStateChanged(RecyclerView view, int scrollState) { + } + + public void onScrolled(RecyclerView view, int dx, int dy) { + if (view.getChildCount() > 0) { + View child = view.getLayoutManager().findViewByPosition(0); + if (child == null || child.getTop() < 0) { + chooserHeader.setElevation(chooserHeaderScrollElevation); + return; + } + } + + chooserHeader.setElevation(defaultElevation); + } + }); + } + @Override // ChooserListCommunicator public boolean isSendAction(Intent targetIntent) { if (targetIntent == null) { @@ -2475,7 +2481,8 @@ public class ChooserActivity extends ResolverActivity implements * row level by this adapter but not on the item level. Individual targets within the row are * handled by {@link ChooserListAdapter} */ - final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + @VisibleForTesting + public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private ChooserListAdapter mChooserListAdapter; private final LayoutInflater mLayoutInflater; @@ -2905,7 +2912,7 @@ public class ChooserActivity extends ResolverActivity implements if (mDirectShareViewHolder != null && canExpandDirectShare) { mDirectShareViewHolder.handleScroll( - mChooserMultiProfilePagerAdapter.getCurrentAdapterView(), y, oldy, + mChooserMultiProfilePagerAdapter.getActiveAdapterView(), y, oldy, getMaxTargetsPerRow()); } } diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index a8a676d03971..6ff844a2eaae 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -246,11 +246,6 @@ public class ChooserListAdapter extends ResolverListAdapter { } @Override - public boolean shouldGetResolvedFilter() { - return true; - } - - @Override public int getCount() { return getRankedTargetCount() + getAlphaTargetCount() + getSelectableServiceTargetCount() + getCallerTargetCount(); diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java index 7d856e1b945d..1c52d0e8f9f1 100644 --- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -16,6 +16,7 @@ package com.android.internal.app; +import android.annotation.Nullable; import android.content.Context; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -77,7 +78,8 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd } @Override - ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) { + @VisibleForTesting + public ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) { return mItems[pageIndex].chooserGridAdapter; } @@ -121,10 +123,19 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd } @Override - RecyclerView getCurrentAdapterView() { + RecyclerView getActiveAdapterView() { return getListViewForIndex(getCurrentPage()); } + @Override + @Nullable + RecyclerView getInactiveAdapterView() { + if (getCount() == 1) { + return null; + } + return getListViewForIndex(1 - getCurrentPage()); + } + class ChooserProfileDescriptor extends ProfileDescriptor { private ChooserActivity.ChooserGridAdapter chooserGridAdapter; private RecyclerView recyclerView; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index b2417b2e79cc..68d6e03f654c 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -59,6 +59,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.Slog; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -67,9 +68,12 @@ import android.view.WindowInsets; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.Button; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ListView; import android.widget.Space; +import android.widget.TabHost; +import android.widget.TabWidget; import android.widget.TextView; import android.widget.Toast; @@ -82,6 +86,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.widget.ResolverDrawerLayout; +import com.android.internal.widget.ViewPager; import java.util.ArrayList; import java.util.Arrays; @@ -147,7 +152,10 @@ public class ResolverActivity extends Activity implements /** * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized. */ - static final boolean ENABLE_TABBED_VIEW = false; + @VisibleForTesting + public static boolean ENABLE_TABBED_VIEW = false; + private static final String TAB_TAG_PERSONAL = "personal"; + private static final String TAB_TAG_WORK = "work"; private final PackageMonitor mPackageMonitor = createPackageMonitor(); @@ -418,12 +426,16 @@ public class ResolverActivity extends Activity implements Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed) { + // We only show the default app for the profile of the current user. The filterLastUsed + // flag determines whether to show a default app and that app is not shown in the + // resolver list. So filterLastUsed should be false for the other profile. ResolverListAdapter personalAdapter = createResolverListAdapter( /* context */ this, /* payloadIntents */ mIntents, initialIntents, rList, - filterLastUsed, + (filterLastUsed && UserHandle.myUserId() + == getPersonalProfileUserHandle().getIdentifier()), mUseLayoutForBrowsables, /* userHandle */ getPersonalProfileUserHandle()); ResolverListAdapter workAdapter = createResolverListAdapter( @@ -431,7 +443,8 @@ public class ResolverActivity extends Activity implements /* payloadIntents */ mIntents, initialIntents, rList, - filterLastUsed, + (filterLastUsed && UserHandle.myUserId() + == getWorkProfileUserHandle().getIdentifier()), mUseLayoutForBrowsables, /* userHandle */ getWorkProfileUserHandle()); return new ResolverMultiProfilePagerAdapter( @@ -495,12 +508,12 @@ public class ResolverActivity extends Activity implements mFooterSpacer = new Space(getApplicationContext()); } else { ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter) - .getCurrentAdapterView().removeFooterView(mFooterSpacer); + .getActiveAdapterView().removeFooterView(mFooterSpacer); } mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, mSystemWindowInsets.bottom)); ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter) - .getCurrentAdapterView().addFooterView(mFooterSpacer); + .getActiveAdapterView().addFooterView(mFooterSpacer); } protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { @@ -817,7 +830,7 @@ public class ResolverActivity extends Activity implements public void onButtonClick(View v) { final int id = v.getId(); - ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + ListView listView = (ListView) mMultiProfilePagerAdapter.getActiveAdapterView(); ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter(); int which = currentListAdapter.hasFilteredItem() ? currentListAdapter.getFilteredPosition() @@ -898,7 +911,10 @@ public class ResolverActivity extends Activity implements @Override // ResolverListCommunicator public void onPostListReady(ResolverListAdapter listAdapter) { - setHeader(); + if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() + == UserHandle.myUserId()) { + setHeader(); + } resetButtonBar(); onListRebuilt(listAdapter); } @@ -913,6 +929,9 @@ public class ResolverActivity extends Activity implements finish(); } } + + final ItemClickListener listener = new ItemClickListener(); + setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener); } protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { @@ -1094,6 +1113,7 @@ public class ResolverActivity extends Activity implements return true; } + @VisibleForTesting public void safelyStartActivity(TargetInfo cti) { // We're dispatching intents that might be coming from legacy apps, so // don't kill ourselves. @@ -1222,9 +1242,6 @@ public class ResolverActivity extends Activity implements + "cannot be null."); } boolean rebuildCompleted = mMultiProfilePagerAdapter.getActiveListAdapter().rebuildList(); - if (mMultiProfilePagerAdapter.getInactiveListAdapter() != null) { - mMultiProfilePagerAdapter.getInactiveListAdapter().rebuildList(); - } if (useLayoutWithDefault()) { mLayoutId = R.layout.resolver_list_with_default; } else { @@ -1272,45 +1289,99 @@ public class ResolverActivity extends Activity implements } } - setupViewVisibilities(count); + setupViewVisibilities(); + + if (hasWorkProfile() && ENABLE_TABBED_VIEW) { + setupProfileTabs(); + } + return false; } - private void setupViewVisibilities(int count) { - if (count == 0 - && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) { - final TextView emptyView = findViewById(R.id.empty); - emptyView.setVisibility(View.VISIBLE); - findViewById(R.id.profile_pager).setVisibility(View.GONE); - } else { - onPrepareAdapterView(mMultiProfilePagerAdapter.getActiveListAdapter()); + private void setupProfileTabs() { + TabHost tabHost = findViewById(R.id.profile_tabhost); + tabHost.setup(); + ViewPager viewPager = findViewById(R.id.profile_pager); + TabHost.TabSpec tabSpec = tabHost.newTabSpec(TAB_TAG_PERSONAL) + .setContent(R.id.profile_pager) + .setIndicator(getString(R.string.resolver_personal_tab)); + tabHost.addTab(tabSpec); + + tabSpec = tabHost.newTabSpec(TAB_TAG_WORK) + .setContent(R.id.profile_pager) + .setIndicator(getString(R.string.resolver_work_tab)); + tabHost.addTab(tabSpec); + + TabWidget tabWidget = tabHost.getTabWidget(); + tabWidget.setVisibility(View.VISIBLE); + resetTabsHeaderStyle(tabWidget); + updateActiveTabStyle(tabHost); + + tabHost.setOnTabChangedListener(tabId -> { + resetTabsHeaderStyle(tabWidget); + updateActiveTabStyle(tabHost); + if (TAB_TAG_PERSONAL.equals(tabId)) { + viewPager.setCurrentItem(0); + } else { + viewPager.setCurrentItem(1); + } + setupViewVisibilities(); + }); + + viewPager.setVisibility(View.VISIBLE); + tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage()); + mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab); + } + + private void resetTabsHeaderStyle(TabWidget tabWidget) { + for (int i = 0; i < tabWidget.getChildCount(); i++) { + TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title); + title.setTextColor(getColor(R.color.resolver_tabs_inactive_color)); + title.setAllCaps(false); + } + } + + private void updateActiveTabStyle(TabHost tabHost) { + TextView title = tabHost.getTabWidget().getChildAt(tabHost.getCurrentTab()) + .findViewById(android.R.id.title); + title.setTextColor(getColor(R.color.resolver_tabs_active_color)); + } + + private void setupViewVisibilities() { + int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); + boolean shouldShowEmptyState = count == 0 + && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0; + //TODO(arangelov): Handle empty state + if (!shouldShowEmptyState) { + addUseDifferentAppLabelIfNecessary(mMultiProfilePagerAdapter.getActiveListAdapter()); } } /** - * Prepare the scrollable view which consumes data in the list adapter. + * Add a label to signify that the user can pick a different app. * @param adapter The adapter used to provide data to item views. */ - public void onPrepareAdapterView(ResolverListAdapter adapter) { - mMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE); + public void addUseDifferentAppLabelIfNecessary(ResolverListAdapter adapter) { final boolean useHeader = adapter.hasFilteredItem(); - final ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); - final ItemClickListener listener = new ItemClickListener(); + if (useHeader) { + FrameLayout stub = findViewById(R.id.stub); + stub.setVisibility(View.VISIBLE); + TextView textView = (TextView) LayoutInflater.from(this).inflate( + R.layout.resolver_different_item_header, null, false); + if (ENABLE_TABBED_VIEW) { + textView.setGravity(Gravity.CENTER); + } + stub.addView(textView); + } + } + + private void setupAdapterListView(ListView listView, ItemClickListener listener) { listView.setOnItemClickListener(listener); listView.setOnItemLongClickListener(listener); if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) { listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); } - - // In case this method is called again (due to activity recreation), avoid adding a new - // header if one is already present. - if (useHeader && listView.getHeaderViewsCount() == 0) { - listView.setHeaderDividersEnabled(true); - listView.addHeaderView(LayoutInflater.from(this).inflate( - R.layout.resolver_different_item_header, listView, false), - null, false); - } } /** @@ -1378,7 +1449,7 @@ public class ResolverActivity extends Activity implements } // When the items load in, if an item was already selected, enable the buttons - ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getActiveAdapterView(); if (currentAdapterView != null && currentAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) { setAlwaysButtonEnabled(true, currentAdapterView.getCheckedItemPosition(), true); @@ -1388,8 +1459,18 @@ public class ResolverActivity extends Activity implements @Override // ResolverListCommunicator public boolean useLayoutWithDefault() { - return mSupportsAlwaysUseOption - && mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem(); + // We only use the default app layout when the profile of the active user has a + // filtered item. We always show the same default app even in the inactive user profile. + boolean currentUserAdapterHasFilteredItem; + if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() + == UserHandle.myUserId()) { + currentUserAdapterHasFilteredItem = + mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem(); + } else { + currentUserAdapterHasFilteredItem = + mMultiProfilePagerAdapter.getInactiveListAdapter().hasFilteredItem(); + } + return mSupportsAlwaysUseOption && currentUserAdapterHasFilteredItem; } /** @@ -1494,9 +1575,8 @@ public class ResolverActivity extends Activity implements .resolveInfoForPosition(position, true) == null) { return; } - ListView currentAdapterView = - (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + (ListView) mMultiProfilePagerAdapter.getActiveAdapterView(); final int checkedPos = currentAdapterView.getCheckedItemPosition(); final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION; if (!useLayoutWithDefault() diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index ef7a347cf7be..d227ec5c1b38 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -193,7 +193,8 @@ public class ResolverListAdapter extends BaseAdapter { mBaseResolveList); } else { currentResolveList = mUnfilteredResolveList = - mResolverListController.getResolversForIntent(shouldGetResolvedFilter(), + mResolverListController.getResolversForIntent( + /* shouldGetResolvedFilter= */ true, mResolverListCommunicator.shouldGetActivityMetadata(), mIntents); if (currentResolveList == null) { @@ -363,10 +364,6 @@ public class ResolverListAdapter extends BaseAdapter { } } - public boolean shouldGetResolvedFilter() { - return mFilterLastUsed; - } - private void addResolveInfoWithAlternates(ResolvedComponentInfo rci) { final int count = rci.getCount(); final Intent intent = rci.getIntentAt(0); diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index abd3eb2453df..0bfe9eb04d28 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -133,7 +133,8 @@ public class ResolverListController { return resolvedComponents; } - UserHandle getUserHandle() { + @VisibleForTesting + public UserHandle getUserHandle() { return mUserHandle; } diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java index d72c52bfe6b6..567ed74670bf 100644 --- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java @@ -16,6 +16,7 @@ package com.android.internal.app; +import android.annotation.Nullable; import android.content.Context; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -81,7 +82,8 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA } @Override - ResolverListAdapter getAdapterForIndex(int pageIndex) { + @VisibleForTesting + public ResolverListAdapter getAdapterForIndex(int pageIndex) { return mItems[pageIndex].resolverListAdapter; } @@ -106,10 +108,19 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA } @Override - ListView getCurrentAdapterView() { + ListView getActiveAdapterView() { return getListViewForIndex(getCurrentPage()); } + @Override + @Nullable + ViewGroup getInactiveAdapterView() { + if (getCount() == 1) { + return null; + } + return getListViewForIndex(1 - getCurrentPage()); + } + class ResolverProfileDescriptor extends ProfileDescriptor { private ResolverListAdapter resolverListAdapter; final ListView listView; diff --git a/core/java/com/android/internal/app/WrapHeightViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java index b017bb44d751..8ec94f159725 100644 --- a/core/java/com/android/internal/app/WrapHeightViewPager.java +++ b/core/java/com/android/internal/app/ResolverViewPager.java @@ -18,39 +18,36 @@ package com.android.internal.app; import android.content.Context; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import com.android.internal.widget.ViewPager; /** - * A {@link ViewPager} which wraps around its first child's height. + * A {@link ViewPager} which wraps around its first child's height and has swiping disabled. * <p>Normally {@link ViewPager} instances expand their height to cover all remaining space in * the layout. - * <p>This class is used for the intent resolver picker's tabbed view to maintain - * consistency with the previous behavior. + * <p>This class is used for the intent resolver and share sheet's tabbed view. */ -public class WrapHeightViewPager extends ViewPager { +public class ResolverViewPager extends ViewPager { - public WrapHeightViewPager(Context context) { + public ResolverViewPager(Context context) { super(context); } - public WrapHeightViewPager(Context context, AttributeSet attrs) { + public ResolverViewPager(Context context, AttributeSet attrs) { super(context, attrs); } - public WrapHeightViewPager(Context context, AttributeSet attrs, int defStyleAttr) { + public ResolverViewPager(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public WrapHeightViewPager(Context context, AttributeSet attrs, + public ResolverViewPager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - // TODO(arangelov): When we have multiple pages, the height should wrap to the currently - // displayed page. Investigate whether onMeasure is called when changing a page, and instead - // of getChildAt(0), use the currently displayed one. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -68,4 +65,14 @@ public class WrapHeightViewPager extends ViewPager { heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return false; + } } diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml index 0c45e45e7980..4e8a41f81c48 100644 --- a/core/res/res/layout/chooser_grid.xml +++ b/core/res/res/layout/chooser_grid.xml @@ -61,10 +61,33 @@ android:layout_height="wrap_content" android:visibility="gone" /> - <com.android.internal.widget.ViewPager - android:id="@+id/profile_pager" + <TabHost + android:id="@+id/profile_tabhost" android:layout_width="match_parent" - android:layout_height="wrap_content"/> + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:background="?attr/colorBackgroundFloating"> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TabWidget + android:id="@android:id/tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + </TabWidget> + <FrameLayout + android:id="@android:id/tabcontent" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <com.android.internal.app.ResolverViewPager + android:id="@+id/profile_pager" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + </FrameLayout> + </LinearLayout> + </TabHost> <TextView android:id="@+id/empty" android:layout_width="match_parent" diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml index c5d891254227..757cd539152d 100644 --- a/core/res/res/layout/resolver_list.xml +++ b/core/res/res/layout/resolver_list.xml @@ -70,14 +70,44 @@ android:background="?attr/colorBackgroundFloating" android:foreground="?attr/dividerVertical" /> - <com.android.internal.app.WrapHeightViewPager - android:id="@+id/profile_pager" + <FrameLayout + android:id="@+id/stub" + android:visibility="gone" android:layout_width="match_parent" android:layout_height="wrap_content" - android:divider="?attr/dividerVertical" - android:footerDividersEnabled="false" - android:headerDividersEnabled="false" - android:dividerHeight="1dp"/> + android:background="?attr/colorBackgroundFloating"/> + + <TabHost + android:id="@+id/profile_tabhost" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:background="?attr/colorBackgroundFloating"> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TabWidget + android:id="@android:id/tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + </TabWidget> + <FrameLayout + android:id="@android:id/tabcontent" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <com.android.internal.app.ResolverViewPager + android:id="@+id/profile_pager" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:divider="?attr/dividerVertical" + android:footerDividersEnabled="false" + android:headerDividersEnabled="false" + android:dividerHeight="1dp"/> + </FrameLayout> + </LinearLayout> + </TabHost> <View android:layout_alwaysShow="true" diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml index 68b991755e73..6d8d3480dc8c 100644 --- a/core/res/res/layout/resolver_list_per_profile.xml +++ b/core/res/res/layout/resolver_list_per_profile.xml @@ -25,7 +25,7 @@ android:nestedScrollingEnabled="true" android:scrollbarStyle="outsideOverlay" android:scrollIndicators="top|bottom" - android:divider="?attr/dividerVertical" + android:divider="@null" android:footerDividersEnabled="false" android:headerDividersEnabled="false" - android:dividerHeight="1dp" />
\ No newline at end of file + android:dividerHeight="0dp" />
\ No newline at end of file diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml index 5b3d929d23a5..b54673834ea9 100644 --- a/core/res/res/layout/resolver_list_with_default.xml +++ b/core/res/res/layout/resolver_list_with_default.xml @@ -151,14 +151,46 @@ android:background="?attr/colorBackgroundFloating" android:foreground="?attr/dividerVertical" /> - <com.android.internal.app.WrapHeightViewPager - android:id="@+id/profile_pager" + <FrameLayout + android:id="@+id/stub" + android:visibility="gone" android:layout_width="match_parent" android:layout_height="wrap_content" - android:dividerHeight="1dp" - android:divider="?attr/dividerVertical" - android:footerDividersEnabled="false" - android:headerDividersEnabled="false"/> + android:background="?attr/colorBackgroundFloating"/> + + <TabHost + android:id="@+id/profile_tabhost" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:background="?attr/colorBackgroundFloating"> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TabWidget + android:id="@android:id/tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone"> + </TabWidget> + <FrameLayout + android:id="@android:id/tabcontent" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <com.android.internal.app.ResolverViewPager + android:id="@+id/profile_pager" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:dividerHeight="1dp" + android:divider="?attr/dividerVertical" + android:footerDividersEnabled="false" + android:headerDividersEnabled="false"/> + </FrameLayout> + </LinearLayout> + </TabHost> + <View android:layout_alwaysShow="true" android:layout_width="match_parent" diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 1dcd389d9d8f..731e2ec95f9e 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -224,4 +224,6 @@ <!-- Resolver/Chooser --> <color name="resolver_text_color_secondary_dark">#ffC4C6C6</color> + <color name="resolver_tabs_active_color">#FF1A73E8</color> + <color name="resolver_tabs_inactive_color">#FF80868B</color> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index bed418dc4c2d..cea6a1524d09 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5319,4 +5319,8 @@ <!-- Text to tell the user that a package has been forced by themselves in the RESTRICTED bucket. [CHAR LIMIT=NONE] --> <string name="as_app_forced_to_restricted_bucket"> <xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string> + + <!-- ResolverActivity - profile tabs --> + <string name="resolver_personal_tab">Personal</string> + <string name="resolver_work_tab">Work</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 357b1f069107..6e67080d3651 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -249,6 +249,9 @@ <java-symbol type="id" name="app_ops" /> <java-symbol type="id" name="profile_pager" /> <java-symbol type="id" name="content_preview_container" /> + <java-symbol type="id" name="profile_tabhost" /> + <java-symbol type="id" name="tabs" /> + <java-symbol type="id" name="tabcontent" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> @@ -3833,4 +3836,12 @@ <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" /> <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" /> + + <!-- Intent resolver and share sheet --> + <java-symbol type="color" name="resolver_tabs_active_color" /> + <java-symbol type="color" name="resolver_tabs_inactive_color" /> + <java-symbol type="string" name="resolver_personal_tab" /> + <java-symbol type="string" name="resolver_work_tab" /> + <java-symbol type="id" name="stub" /> + </resources> |