summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java151
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java355
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java128
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java309
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java9
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java16
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java113
-rw-r--r--core/java/com/android/internal/app/WrapHeightViewPager.java71
-rw-r--r--core/res/res/layout/chooser_grid.xml14
-rw-r--r--core/res/res/layout/chooser_list_per_profile.xml27
-rw-r--r--core/res/res/layout/resolver_list.xml16
-rw-r--r--core/res/res/layout/resolver_list_per_profile.xml31
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml16
-rw-r--r--core/res/res/values/symbols.xml3
14 files changed, 1007 insertions, 252 deletions
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..2fd5bfd71656
--- /dev/null
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 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.internal.app;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.UserHandle;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.PagerAdapter;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.widget.ViewPager;
+
+/**
+ * Skeletal {@link PagerAdapter} implementation of a work or personal profile page for
+ * intent resolution (including share sheet).
+ */
+public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
+
+ static final int PROFILE_PERSONAL = 0;
+ static final int PROFILE_WORK = 1;
+ @IntDef({PROFILE_PERSONAL, PROFILE_WORK})
+ @interface Profile {}
+
+ private final Context mContext;
+ private int mCurrentPage;
+
+ AbstractMultiProfilePagerAdapter(Context context, int currentPage) {
+ mContext = Preconditions.checkNotNull(context);
+ mCurrentPage = currentPage;
+ }
+
+ Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Sets this instance of this class as {@link ViewPager}'s {@link PagerAdapter} and sets
+ * an {@link ViewPager.OnPageChangeListener} where it keeps track of the currently displayed
+ * 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;
+ getCurrentListAdapter().rebuildList();
+ }
+ });
+ viewPager.setAdapter(this);
+ }
+
+ @Override
+ public ViewGroup instantiateItem(ViewGroup container, int position) {
+ final ProfileDescriptor profileDescriptor = getItem(position);
+ setupListAdapter(position);
+ container.addView(profileDescriptor.rootView);
+ return profileDescriptor.rootView;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object view) {
+ container.removeView((View) view);
+ }
+
+ @Override
+ public int getCount() {
+ return getItemCount();
+ }
+
+ protected int getCurrentPage() {
+ return mCurrentPage;
+ }
+
+ UserHandle getCurrentUserHandle() {
+ return getCurrentListAdapter().mResolverListController.getUserHandle();
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return null;
+ }
+
+ /**
+ * Returns the {@link ProfileDescriptor} relevant to the given <code>pageIndex</code>.
+ * <ul>
+ * <li>For a device with only one user, <code>pageIndex</code> value of
+ * <code>0</code> would return the personal profile {@link ProfileDescriptor}.</li>
+ * <li>For a device with a work profile, <code>pageIndex</code> value of <code>0</code> would
+ * return the personal profile {@link ProfileDescriptor}, and <code>pageIndex</code> value of
+ * <code>1</code> would return the work profile {@link ProfileDescriptor}.</li>
+ * </ul>
+ */
+ abstract ProfileDescriptor getItem(int pageIndex);
+
+ /**
+ * Returns the number of {@link ProfileDescriptor} objects.
+ * <p>For a normal consumer device with only one user returns <code>1</code>.
+ * <p>For a device with a work profile returns <code>2</code>.
+ */
+ abstract int getItemCount();
+
+ /**
+ * Responsible for assigning an adapter to the list view for the relevant page, specified by
+ * <code>pageIndex</code>, and other list view-related initialization procedures.
+ */
+ abstract void setupListAdapter(int pageIndex);
+
+ /**
+ * Returns the adapter of the list view for the relevant page specified by
+ * <code>pageIndex</code>.
+ * <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 ResolverListAdapter getCurrentListAdapter();
+
+ abstract Object getCurrentRootAdapter();
+
+ abstract ViewGroup getCurrentAdapterView();
+
+ protected class ProfileDescriptor {
+ final ViewGroup rootView;
+ ProfileDescriptor(ViewGroup rootView) {
+ this.rootView = rootView;
+ }
+ }
+} \ 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 183e9a6faf09..1af39265dbcb 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -98,6 +98,7 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
@@ -173,7 +174,6 @@ public class ChooserActivity extends ResolverActivity implements
@VisibleForTesting
public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
- private static final int SINGLE_CELL_SPAN_SIZE = 1;
private boolean mIsAppPredictorComponentAvailable;
private AppPredictor mAppPredictor;
@@ -229,9 +229,6 @@ public class ChooserActivity extends ResolverActivity implements
private long mQueriedTargetServicesTimeMs;
private long mQueriedSharingShortcutsTimeMs;
- private RecyclerView mRecyclerView;
- private ChooserListAdapter mChooserListAdapter;
- private ChooserGridAdapter mChooserGridAdapter;
private int mChooserRowServiceSpacing;
private int mCurrAvailableWidth = 0;
@@ -265,6 +262,9 @@ public class ChooserActivity extends ResolverActivity implements
private ContentPreviewCoordinator mPreviewCoord;
+ @VisibleForTesting
+ protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
+
private class ContentPreviewCoordinator {
private static final int IMAGE_FADE_IN_MILLIS = 150;
private static final int IMAGE_LOAD_TIMEOUT = 1;
@@ -362,8 +362,8 @@ public class ChooserActivity extends ResolverActivity implements
Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load"
+ " within " + mImageLoadTimeoutMillis + "ms.");
collapseParentView();
- if (mChooserGridAdapter != null) {
- mChooserGridAdapter.hideContentPreview();
+ if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview();
}
mHideParentOnFail = false;
}
@@ -431,13 +431,14 @@ public class ChooserActivity extends ResolverActivity implements
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
sendVoiceChoicesIfNeeded();
- mChooserListAdapter.completeServiceTargetLoading();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .completeServiceTargetLoading();
}
}
@Override
public void handleMessage(Message msg) {
- if (mChooserListAdapter == null || isDestroyed()) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter() == null || isDestroyed()) {
return;
}
@@ -452,8 +453,10 @@ public class ChooserActivity extends ResolverActivity implements
break;
}
if (sri.resultTargets != null) {
- mChooserListAdapter.addServiceResults(sri.originalTarget,
- sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET);
+ // TODO(arangelov): Instead of using getCurrentListAdapter(), pass the
+ // profileId as part of the message.
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ sri.originalTarget, sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET);
}
unbindService(sri.connection);
sri.connection.destroy();
@@ -476,15 +479,15 @@ public class ChooserActivity extends ResolverActivity implements
Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; ");
}
- mChooserListAdapter.refreshListView();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().refreshListView();
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT");
final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj;
if (resultInfo.resultTargets != null) {
- mChooserListAdapter.addServiceResults(resultInfo.originalTarget,
- resultInfo.resultTargets, msg.arg1);
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1);
}
break;
@@ -504,6 +507,7 @@ 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;
@@ -638,19 +642,24 @@ public class ChooserActivity extends ResolverActivity implements
if (appPredictor != null) {
mDirectShareAppTargetCache = new HashMap<>();
mAppPredictorCallback = resultList -> {
+ //TODO(arangelov) Take care of edge case when callback called after swiping tabs
if (isFinishing() || isDestroyed()) {
return;
}
- if (mChooserListAdapter.getCount() == 0) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
return;
}
if (resultList.isEmpty()) {
// APS may be disabled, so try querying targets ourselves.
- queryDirectShareTargets(mChooserListAdapter, true);
+ //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents.
+ // Investigate implications for work tab.
+ queryDirectShareTargets(
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter(), true);
return;
}
final List<DisplayResolveInfo> driList =
- getDisplayResolveInfos(mChooserListAdapter);
+ getDisplayResolveInfos(
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter());
final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
new ArrayList<>();
for (AppTarget appTarget : resultList) {
@@ -684,21 +693,22 @@ public class ChooserActivity extends ResolverActivity implements
final float chooserHeaderScrollElevation =
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
- mRecyclerView.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;
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView().addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ public void onScrollStateChanged(RecyclerView view, int scrollState) {
}
- }
- chooserHeader.setElevation(defaultElevation);
- }
+ 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(
@@ -738,6 +748,71 @@ public class ChooserActivity extends ResolverActivity implements
return context.getSharedPreferences(prefsFile, MODE_PRIVATE);
}
+ @Override
+ protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForTwoProfiles(
+ initialIntents, rList, filterLastUsed);
+ } else {
+ mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForOneProfile(
+ initialIntents, rList, filterLastUsed);
+ }
+ return mChooserMultiProfilePagerAdapter;
+ }
+
+ private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ChooserGridAdapter adapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ return new ChooserMultiProfilePagerAdapter(
+ /* context */ this,
+ adapter);
+ }
+
+ private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ChooserGridAdapter personalAdapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getPersonalProfileUserHandle());
+ ChooserGridAdapter workAdapter = createChooserGridAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getWorkProfileUserHandle());
+ return new ChooserMultiProfilePagerAdapter(
+ /* context */ this,
+ personalAdapter,
+ workAdapter,
+ /* defaultProfile */ getCurrentProfile());
+ }
+
+ @Override
+ protected boolean postRebuildList(boolean rebuildCompleted) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().maybeLogActionShareWithPreview();
+ return postRebuildListInternal(rebuildCompleted);
+ }
+
/**
* Returns true if app prediction service is defined and the component exists on device.
*/
@@ -776,7 +851,7 @@ public class ChooserActivity extends ResolverActivity implements
* set up)
*/
protected boolean isWorkProfile() {
- return ((UserManager) getSystemService(Context.USER_SERVICE))
+ return getSystemService(UserManager.class)
.getUserInfo(UserHandle.myUserId()).isManagedProfile();
}
@@ -785,7 +860,9 @@ public class ChooserActivity extends ResolverActivity implements
return new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
- mAdapter.handlePackagesChanged();
+ // TODO(arangelov): Dispatch this to all adapters when we have the helper methods
+ // in a follow-up CL
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
};
@@ -1239,36 +1316,14 @@ public class ChooserActivity extends ResolverActivity implements
}
@Override
- public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
- mRecyclerView = findViewById(R.id.resolver_list);
- if (!isVisible) {
- mRecyclerView.setVisibility(View.GONE);
- return;
- }
- mRecyclerView.setVisibility(View.VISIBLE);
+ public void onPrepareAdapterView(ResolverListAdapter adapter) {
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
- mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets),
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+ /* origTarget */ null,
+ Lists.newArrayList(mCallerChooserTargets),
TARGET_TYPE_DEFAULT);
}
- mChooserGridAdapter = new ChooserGridAdapter(mChooserListAdapter);
- GridLayoutManager glm = (GridLayoutManager) mRecyclerView.getLayoutManager();
- glm.setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
- glm.setSpanSizeLookup(
- new GridLayoutManager.SpanSizeLookup() {
- @Override
- public int getSpanSize(int position) {
- return mChooserGridAdapter.getItemViewType(position)
- == ChooserGridAdapter.VIEW_TYPE_NORMAL
- ? SINGLE_CELL_SPAN_SIZE
- : glm.getSpanCount();
- }
- });
- }
-
- @Override
- protected boolean postRebuildList(boolean rebuildCompleted) {
- mChooserListAdapter = (ChooserListAdapter) mAdapter;
- return postRebuildListInternal(rebuildCompleted);
}
@Override
@@ -1348,7 +1403,10 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void startSelected(int which, boolean always, boolean filtered) {
- TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered);
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ TargetInfo targetInfo = currentListAdapter
+ .targetInfoForPosition(which, filtered);
if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) {
return;
}
@@ -1356,7 +1414,7 @@ public class ChooserActivity extends ResolverActivity implements
final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
super.startSelected(which, always, filtered);
- if (mChooserListAdapter.getCount() > 0) {
+ if (currentListAdapter.getCount() > 0) {
// Log the index of which type of target the user picked.
// Lower values mean the ranking was better.
int cat = 0;
@@ -1364,13 +1422,12 @@ public class ChooserActivity extends ResolverActivity implements
int directTargetAlsoRanked = -1;
int numCallerProvided = 0;
HashedStringCache.HashResult directTargetHashed = null;
- switch (mChooserListAdapter.getPositionTargetType(which)) {
+ switch (currentListAdapter.getPositionTargetType(which)) {
case ChooserListAdapter.TARGET_SERVICE:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
// Log the package name + target name to answer the question if most users
// share to mostly the same person or to a bunch of different people.
- ChooserTarget target =
- mChooserListAdapter.getChooserTargetForValue(value);
+ ChooserTarget target = currentListAdapter.getChooserTargetForValue(value);
directTargetHashed = HashedStringCache.getInstance().hashString(
this,
TAG,
@@ -1386,8 +1443,8 @@ public class ChooserActivity extends ResolverActivity implements
case ChooserListAdapter.TARGET_CALLER:
case ChooserListAdapter.TARGET_STANDARD:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
- value -= mChooserListAdapter.getSelectableServiceTargetCount();
- numCallerProvided = mChooserListAdapter.getCallerTargetCount();
+ value -= currentListAdapter.getSelectableServiceTargetCount();
+ numCallerProvided = currentListAdapter.getCallerTargetCount();
break;
case ChooserListAdapter.TARGET_STANDARD_AZ:
// A-Z targets are unranked standard targets; we use -1 to mark that they
@@ -1429,11 +1486,13 @@ public class ChooserActivity extends ResolverActivity implements
private int getRankedPosition(SelectableTargetInfo targetInfo) {
String targetPackageName =
targetInfo.getChooserTarget().getComponentName().getPackageName();
- int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(),
- MAX_LOG_RANK_POSITION);
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ int maxRankedResults = Math.min(currentListAdapter.mDisplayList.size(),
+ MAX_LOG_RANK_POSITION);
for (int i = 0; i < maxRankedResults; i++) {
- if (mChooserListAdapter.mDisplayList.get(i)
+ if (currentListAdapter.mDisplayList.get(i)
.getResolveInfo().activityInfo.packageName.equals(targetPackageName)) {
return i;
}
@@ -1577,6 +1636,7 @@ public class ChooserActivity extends ResolverActivity implements
}
}
// Default to just querying ShortcutManager if AppPredictor not present.
+ //TODO(arangelov) we're using mIntents here, investicate possible implications on work tab
final IntentFilter filter = getTargetIntentFilter();
if (filter == null) {
return;
@@ -1584,6 +1644,7 @@ public class ChooserActivity extends ResolverActivity implements
final List<DisplayResolveInfo> driList = getDisplayResolveInfos(adapter);
AsyncTask.execute(() -> {
+ //TODO(arangelov) use the selected probile tab's ShortcutManager
ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
sendShareShortcutInfoList(resultList, driList, null);
@@ -1779,9 +1840,11 @@ public class ChooserActivity extends ResolverActivity implements
final ResolveInfo ri = info.getResolveInfo();
Intent targetIntent = getTargetIntent();
if (ri != null && ri.activityInfo != null && targetIntent != null) {
- if (mAdapter != null) {
- mAdapter.updateModel(info.getResolvedComponentName());
- mAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(),
+ ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ if (currentListAdapter != null) {
+ currentListAdapter.updateModel(info.getResolvedComponentName());
+ currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(),
targetIntent.getAction());
}
if (DEBUG) {
@@ -1956,8 +2019,9 @@ public class ChooserActivity extends ResolverActivity implements
Intent targetIntent,
String referrerPackageName,
int launchedFromUid,
+ UserHandle userId,
AbstractResolverComparator resolverComparator) {
- super(context, pm, targetIntent, referrerPackageName, launchedFromUid,
+ super(context, pm, targetIntent, referrerPackageName, launchedFromUid, userId,
resolverComparator);
}
@@ -1980,17 +2044,18 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- @Override
- public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
- Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, boolean useLayoutForBrowsables) {
- return new ChooserListAdapter(context, payloadIntents,
- initialIntents, rList, filterLastUsed, createListController(),
- useLayoutForBrowsables, this, this);
+ @VisibleForTesting
+ public ChooserGridAdapter createChooserGridAdapter(Context context,
+ List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
+ return new ChooserGridAdapter(
+ new ChooserListAdapter(context, payloadIntents, initialIntents, rList,
+ filterLastUsed, createListController(userHandle), useLayoutForBrowsables,
+ this, this));
}
@VisibleForTesting
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
AppPredictor appPredictor = getAppPredictorForShareActivitesIfEnabled();
AbstractResolverComparator resolverComparator;
if (appPredictor != null) {
@@ -2008,6 +2073,7 @@ public class ChooserActivity extends ResolverActivity implements
getTargetIntent(),
getReferrerPackageName(),
mLaunchedFromUid,
+ userHandle,
resolverComparator);
}
@@ -2041,8 +2107,8 @@ public class ChooserActivity extends ResolverActivity implements
}
private void handleScroll(View view, int x, int y, int oldx, int oldy) {
- if (mChooserGridAdapter != null) {
- mChooserGridAdapter.handleScroll(view, y, oldy);
+ if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
+ mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().handleScroll(view, y, oldy);
}
}
@@ -2053,37 +2119,42 @@ public class ChooserActivity extends ResolverActivity implements
*/
private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- if (mChooserGridAdapter == null || mRecyclerView == null) {
+ if (mChooserMultiProfilePagerAdapter == null) {
+ return;
+ }
+ RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getCurrentAdapterView();
+ ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter();
+ if (gridAdapter == null || recyclerView == null) {
return;
}
final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
- if (mChooserGridAdapter.consumeLayoutRequest()
- || mChooserGridAdapter.calculateChooserTargetWidth(availableWidth)
- || mRecyclerView.getAdapter() == null
+ if (gridAdapter.consumeLayoutRequest()
+ || gridAdapter.calculateChooserTargetWidth(availableWidth)
+ || recyclerView.getAdapter() == null
|| availableWidth != mCurrAvailableWidth) {
mCurrAvailableWidth = availableWidth;
- mRecyclerView.setAdapter(mChooserGridAdapter);
- ((GridLayoutManager) mRecyclerView.getLayoutManager())
- .setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
+ recyclerView.setAdapter(gridAdapter);
+ ((GridLayoutManager) recyclerView.getLayoutManager())
+ .setSpanCount(gridAdapter.getMaxTargetsPerRow());
getMainThreadHandler().post(() -> {
- if (mResolverDrawerLayout == null || mChooserGridAdapter == null) {
+ if (mResolverDrawerLayout == null || gridAdapter == null) {
return;
}
final int bottomInset = mSystemWindowInsets != null
? mSystemWindowInsets.bottom : 0;
int offset = bottomInset;
- int rowsToShow = mChooserGridAdapter.getContentPreviewRowCount()
- + mChooserGridAdapter.getProfileRowCount()
- + mChooserGridAdapter.getServiceTargetRowCount()
- + mChooserGridAdapter.getCallerAndRankedTargetRowCount();
+ int rowsToShow = gridAdapter.getContentPreviewRowCount()
+ + gridAdapter.getProfileRowCount()
+ + gridAdapter.getServiceTargetRowCount()
+ + gridAdapter.getCallerAndRankedTargetRowCount();
// then this is most likely not a SEND_* action, so check
// the app target count
if (rowsToShow == 0) {
- rowsToShow = mChooserGridAdapter.getRowCount();
+ rowsToShow = gridAdapter.getRowCount();
}
// still zero? then use a default height and leave, which
@@ -2097,9 +2168,9 @@ public class ChooserActivity extends ResolverActivity implements
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
- for (int i = 0, childCount = mRecyclerView.getChildCount();
+ for (int i = 0, childCount = recyclerView.getChildCount();
i < childCount && rowsToShow > 0; i++) {
- View child = mRecyclerView.getChildAt(i);
+ View child = recyclerView.getChildAt(i);
if (((GridLayoutManager.LayoutParams)
child.getLayoutParams()).getSpanIndex() != 0) {
continue;
@@ -2107,9 +2178,9 @@ public class ChooserActivity extends ResolverActivity implements
int height = child.getHeight();
offset += height;
- if (mChooserGridAdapter.getTargetType(
- mRecyclerView.getChildAdapterPosition(child))
- == mChooserListAdapter.TARGET_SERVICE) {
+ if (gridAdapter.getTargetType(
+ recyclerView.getChildAdapterPosition(child))
+ == ChooserListAdapter.TARGET_SERVICE) {
directShareHeight = height;
}
rowsToShow--;
@@ -2145,13 +2216,13 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ResolverListCommunicator
public void onHandlePackagesChanged() {
mServicesRequested.clear();
- mAdapter.notifyDataSetChanged();
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter().notifyDataSetChanged();
super.onHandlePackagesChanged();
}
@Override // SelectableTargetInfoCommunicator
public ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info) {
- return mChooserListAdapter.makePresentationGetter(info);
+ return mChooserMultiProfilePagerAdapter.getCurrentListAdapter().makePresentationGetter(info);
}
@Override // SelectableTargetInfoCommunicator
@@ -2161,9 +2232,9 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ChooserListCommunicator
public int getMaxRankedTargets() {
- return mChooserGridAdapter == null
+ return mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() == null
? ChooserGridAdapter.MAX_TARGETS_PER_ROW_PORTRAIT
- : mChooserGridAdapter.getMaxTargetsPerRow();
+ : mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().getMaxTargetsPerRow();
}
@Override // ChooserListCommunicator
@@ -2174,19 +2245,21 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void onListRebuilt() {
- if (mChooserListAdapter.mDisplayList == null
- || mChooserListAdapter.mDisplayList.isEmpty()) {
- mChooserListAdapter.notifyDataSetChanged();
+ final ChooserListAdapter currentListAdapter =
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+ if (currentListAdapter.mDisplayList == null
+ || currentListAdapter.mDisplayList.isEmpty()) {
+ currentListAdapter.notifyDataSetChanged();
} else {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
- mChooserListAdapter.updateAlphabeticalList();
+ currentListAdapter.updateAlphabeticalList();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
- mChooserListAdapter.notifyDataSetChanged();
+ currentListAdapter.notifyDataSetChanged();
}
}.execute();
}
@@ -2202,14 +2275,14 @@ public class ChooserActivity extends ResolverActivity implements
Log.d(TAG, "querying direct share targets from ShortcutManager");
}
- queryDirectShareTargets(mChooserListAdapter, false);
+ queryDirectShareTargets(currentListAdapter, false);
}
if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
if (DEBUG) {
Log.d(TAG, "List built querying services");
}
- queryTargetServices(mChooserListAdapter);
+ queryTargetServices(currentListAdapter);
}
}
@@ -2250,8 +2323,8 @@ public class ChooserActivity extends ResolverActivity implements
false/* always */, true/* filterd */));
itemView.setOnLongClickListener(v -> {
showTargetDetails(
- mChooserListAdapter.resolveInfoForPosition(
- mListPosition, true/* filtered */));
+ mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(mListPosition, /* filtered */ true));
return true;
});
}
@@ -2259,6 +2332,29 @@ public class ChooserActivity extends ResolverActivity implements
}
/**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ return insets.consumeSystemWindowInsets();
+ }
+
+ /**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ public void onButtonClick(View v) {}
+
+ /**
+ * Intentionally override the {@link ResolverActivity} implementation as we only need that
+ * implementation for the intent resolver case.
+ */
+ @Override
+ protected void resetButtonBar() {}
+
+ /**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
* row level by this adapter but not on the item level. Individual targets within the row are
@@ -2329,12 +2425,11 @@ public class ChooserActivity extends ResolverActivity implements
return false;
}
- private int getMaxTargetsPerRow() {
+ int getMaxTargetsPerRow() {
int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
if (shouldDisplayLandscape(getResources().getConfiguration().orientation)) {
maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
}
-
return maxTargets;
}
@@ -2477,10 +2572,6 @@ public class ChooserActivity extends ResolverActivity implements
private ViewGroup createContentPreviewView(ViewGroup parent) {
Intent targetIntent = getTargetIntent();
int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
-
- getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
- .setSubtype(previewType));
-
return displayContentPreview(previewType, targetIntent, mLayoutInflater, parent);
}
@@ -2667,6 +2758,7 @@ public class ChooserActivity extends ResolverActivity implements
for (int i = 0; i < columnCount; i++) {
final View v = holder.getView(i);
+
if (start + i <= end) {
holder.setViewVisibility(i, View.VISIBLE);
holder.setItemIndex(i, start + i);
@@ -2712,9 +2804,29 @@ public class ChooserActivity extends ResolverActivity implements
&& !isInMultiWindowMode();
if (mDirectShareViewHolder != null && canExpandDirectShare) {
- mDirectShareViewHolder.handleScroll(mRecyclerView, y, oldy, getMaxTargetsPerRow());
+ mDirectShareViewHolder.handleScroll(
+ mChooserMultiProfilePagerAdapter.getCurrentAdapterView(), y, oldy,
+ getMaxTargetsPerRow());
}
}
+
+ public ChooserListAdapter getListAdapter() {
+ return mChooserListAdapter;
+ }
+
+ void maybeLogActionShareWithPreview() {
+ if (getContentPreviewRowCount() == 0) {
+ return;
+ }
+ Intent targetIntent = getTargetIntent();
+ int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+ getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+ .setSubtype(previewType));
+ }
+
+ boolean shouldCellSpan(int position) {
+ return getItemViewType(position) == VIEW_TYPE_NORMAL;
+ }
}
/**
@@ -2898,7 +3010,8 @@ public class ChooserActivity extends ResolverActivity implements
// only expand if we have more than maxTargetsPerRow, and delay that decision
// until they start to scroll
- if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+ if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getSelectableServiceTargetCount() <= maxTargetsPerRow) {
mHideDirectShareExpansion = true;
return;
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..aa8ab2865d92
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 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.internal.app;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.GridLayoutManager;
+import com.android.internal.widget.PagerAdapter;
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * A {@link PagerAdapter} which describes the work and personal profile share sheet screens.
+ */
+@VisibleForTesting
+public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
+ private static final int SINGLE_CELL_SPAN_SIZE = 1;
+
+ private final ChooserProfileDescriptor[] mItems;
+
+ ChooserMultiProfilePagerAdapter(Context context,
+ ChooserActivity.ChooserGridAdapter adapter) {
+ super(context, /* currentPage */ 0);
+ mItems = new ChooserProfileDescriptor[] {
+ createProfileDescriptor(adapter)
+ };
+ }
+
+ ChooserMultiProfilePagerAdapter(Context context,
+ ChooserActivity.ChooserGridAdapter personalAdapter,
+ ChooserActivity.ChooserGridAdapter workAdapter,
+ @Profile int defaultProfile) {
+ super(context, /* currentPage */ defaultProfile);
+ mItems = new ChooserProfileDescriptor[] {
+ createProfileDescriptor(personalAdapter),
+ createProfileDescriptor(workAdapter)
+ };
+ }
+
+ private ChooserProfileDescriptor createProfileDescriptor(
+ ChooserActivity.ChooserGridAdapter adapter) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final ViewGroup rootView =
+ (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile, null, false);
+ return new ChooserProfileDescriptor(rootView, adapter);
+ }
+
+ RecyclerView getListViewForIndex(int index) {
+ return getItem(index).recyclerView;
+ }
+
+ @Override
+ ChooserProfileDescriptor getItem(int pageIndex) {
+ return mItems[pageIndex];
+ }
+
+ @Override
+ int getItemCount() {
+ return mItems.length;
+ }
+
+ @Override
+ ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) {
+ return mItems[pageIndex].chooserGridAdapter;
+ }
+
+ @Override
+ void setupListAdapter(int pageIndex) {
+ final RecyclerView recyclerView = getItem(pageIndex).recyclerView;
+ ChooserActivity.ChooserGridAdapter chooserGridAdapter =
+ getItem(pageIndex).chooserGridAdapter;
+ recyclerView.setAdapter(chooserGridAdapter);
+ GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager();
+ glm.setSpanCount(chooserGridAdapter.getMaxTargetsPerRow());
+ glm.setSpanSizeLookup(
+ new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ return chooserGridAdapter.shouldCellSpan(position)
+ ? SINGLE_CELL_SPAN_SIZE
+ : glm.getSpanCount();
+ }
+ });
+ }
+
+ @Override
+ @VisibleForTesting
+ public ChooserListAdapter getCurrentListAdapter() {
+ return getAdapterForIndex(getCurrentPage()).getListAdapter();
+ }
+
+ @Override
+ ChooserActivity.ChooserGridAdapter getCurrentRootAdapter() {
+ return getAdapterForIndex(getCurrentPage());
+ }
+
+ @Override
+ RecyclerView getCurrentAdapterView() {
+ return getListViewForIndex(getCurrentPage());
+ }
+
+ class ChooserProfileDescriptor extends ProfileDescriptor {
+ private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
+ private RecyclerView recyclerView;
+ ChooserProfileDescriptor(ViewGroup rootView, ChooserActivity.ChooserGridAdapter adapter) {
+ super(rootView);
+ chooserGridAdapter = adapter;
+ recyclerView = rootView.findViewById(R.id.resolver_list);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3c028d71b40d..9cf5e9f47e7f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -18,11 +18,15 @@ package com.android.internal.app;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
+import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_WORK;
+
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.VoiceInteractor.PickOptionRequest;
@@ -72,6 +76,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.Profile;
import com.android.internal.app.chooser.DisplayResolveInfo;
import com.android.internal.app.chooser.TargetInfo;
import com.android.internal.content.PackageMonitor;
@@ -99,10 +104,7 @@ public class ResolverActivity extends Activity implements
public ResolverActivity() {
}
- @UnsupportedAppUsage
- protected ResolverListAdapter mAdapter;
private boolean mSafeForwardingMode;
- private AbsListView mAdapterView;
private Button mAlwaysButton;
private Button mOnceButton;
protected View mProfileView;
@@ -143,8 +145,16 @@ public class ResolverActivity extends Activity implements
private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
private static final String OPEN_LINKS_COMPONENT_KEY = "app_link_state";
+ /**
+ * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
+ */
+ static final boolean ENABLE_TABBED_VIEW = false;
+
private final PackageMonitor mPackageMonitor = createPackageMonitor();
+ @VisibleForTesting
+ protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter;
+
// Intent extra for connected audio devices
public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
@@ -230,7 +240,7 @@ public class ResolverActivity extends Activity implements
return new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
@@ -325,15 +335,13 @@ public class ResolverActivity extends Activity implements
mSupportsAlwaysUseOption = supportsAlwaysUseOption;
- // The last argument of createAdapter is whether to do special handling
+ // The last argument of createResolverListAdapter is whether to do special handling
// of the last used choice to highlight it in the list. We need to always
// turn this off when running under voice interaction, since it results in
// a more complicated UI that the current voice interaction flow is not able
// to handle.
boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
- mAdapter = createAdapter(this, mIntents, initialIntents, rList,
- filterLastUsed, mUseLayoutForBrowsables);
-
+ mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
if (configureContentView()) {
return;
}
@@ -364,15 +372,96 @@ public class ResolverActivity extends Activity implements
}
final Set<String> categories = intent.getCategories();
- MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ MetricsLogger.action(this, mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
: MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
intent.getAction() + ":" + intent.getType() + ":"
+ (categories != null ? Arrays.toString(categories.toArray()) : ""));
}
+ protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ AbstractMultiProfilePagerAdapter resolverMultiProfilePagerAdapter = null;
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ resolverMultiProfilePagerAdapter =
+ createResolverMultiProfilePagerAdapterForTwoProfiles(
+ initialIntents, rList, filterLastUsed);
+ } else {
+ resolverMultiProfilePagerAdapter = createResolverMultiProfilePagerAdapterForOneProfile(
+ initialIntents, rList, filterLastUsed);
+ }
+ return resolverMultiProfilePagerAdapter;
+ }
+
+ private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForOneProfile(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList, boolean filterLastUsed) {
+ ResolverListAdapter adapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ return new ResolverMultiProfilePagerAdapter(
+ /* context */ this,
+ adapter);
+ }
+
+ private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles(
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed) {
+ ResolverListAdapter personalAdapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getPersonalProfileUserHandle());
+ ResolverListAdapter workAdapter = createResolverListAdapter(
+ /* context */ this,
+ /* payloadIntents */ mIntents,
+ initialIntents,
+ rList,
+ filterLastUsed,
+ mUseLayoutForBrowsables,
+ /* userHandle */ getWorkProfileUserHandle());
+ return new ResolverMultiProfilePagerAdapter(
+ /* context */ this,
+ personalAdapter,
+ workAdapter,
+ /* defaultProfile */ getCurrentProfile());
+ }
+
+ protected @Profile int getCurrentProfile() {
+ return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
+ }
+
+ protected UserHandle getPersonalProfileUserHandle() {
+ return UserHandle.of(ActivityManager.getCurrentUser());
+ }
+ protected @Nullable UserHandle getWorkProfileUserHandle() {
+ UserManager userManager = getSystemService(UserManager.class);
+ for (final UserInfo userInfo : userManager.getProfiles(ActivityManager.getCurrentUser())) {
+ if (userInfo.isManagedProfile()) {
+ return userInfo.getUserHandle();
+ }
+ }
+ return null;
+ }
+
+ protected boolean hasWorkProfile() {
+ return getWorkProfileUserHandle() != null;
+ }
+
protected void onProfileClick(View v) {
- final DisplayResolveInfo dri = mAdapter.getOtherProfile();
+ final DisplayResolveInfo dri =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
if (dri == null) {
return;
}
@@ -395,11 +484,13 @@ public class ResolverActivity extends Activity implements
if (mFooterSpacer == null) {
mFooterSpacer = new Space(getApplicationContext());
} else {
- ((ListView) mAdapterView).removeFooterView(mFooterSpacer);
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().removeFooterView(mFooterSpacer);
}
mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
mSystemWindowInsets.bottom));
- ((ListView) mAdapterView).addFooterView(mFooterSpacer);
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().addFooterView(mFooterSpacer);
} else {
View emptyView = findViewById(R.id.empty);
if (emptyView != null) {
@@ -417,7 +508,7 @@ public class ResolverActivity extends Activity implements
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
if (mSystemWindowInsets != null) {
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
@@ -432,9 +523,10 @@ public class ResolverActivity extends Activity implements
return;
}
- final Option[] options = new Option[mAdapter.getCount()];
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getCount();
+ final Option[] options = new Option[count];
for (int i = 0, N = options.length; i < N; i++) {
- TargetInfo target = mAdapter.getItem(i);
+ TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter().getItem(i);
if (target == null) {
// If this occurs, a new set of targets is being loaded. Let that complete,
// and have the next call to send voice choices proceed instead.
@@ -483,8 +575,9 @@ public class ResolverActivity extends Activity implements
return;
}
- final DisplayResolveInfo dri = mAdapter.getOtherProfile();
- if (dri != null) {
+ final DisplayResolveInfo dri =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
+ if (dri != null && !ENABLE_TABBED_VIEW) {
mProfileView.setVisibility(View.VISIBLE);
View text = mProfileView.findViewById(R.id.profile_button);
if (!(text instanceof TextView)) {
@@ -535,7 +628,8 @@ public class ResolverActivity extends Activity implements
// While there may already be a filtered item, we can only use it in the title if the list
// is already sorted and all information relevant to it is already in the list.
- final boolean named = mAdapter.getFilteredPosition() >= 0;
+ final boolean named =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredPosition() >= 0;
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
return getString(defaultTitleRes);
} else if (isHttpSchemeAndViewAction(intent)) {
@@ -544,12 +638,14 @@ public class ResolverActivity extends Activity implements
String dialogTitle = null;
if (named && !mUseLayoutForBrowsables) {
dialogTitle = getString(ActionTitle.BROWSABLE_APP_TITLE_RES,
- mAdapter.getFilteredItem().getDisplayLabel());
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+ .getDisplayLabel());
} else if (named && mUseLayoutForBrowsables) {
dialogTitle = getString(ActionTitle.BROWSABLE_HOST_APP_TITLE_RES,
intent.getData().getHost(),
- mAdapter.getFilteredItem().getDisplayLabel());
- } else if (mAdapter.areAllTargetsBrowsers()) {
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+ .getDisplayLabel());
+ } else if (mMultiProfilePagerAdapter.getCurrentListAdapter().areAllTargetsBrowsers()) {
dialogTitle = getString(ActionTitle.BROWSABLE_TITLE_RES);
} else {
dialogTitle = getString(ActionTitle.BROWSABLE_HOST_TITLE_RES,
@@ -558,7 +654,8 @@ public class ResolverActivity extends Activity implements
return dialogTitle;
} else {
return named
- ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
+ ? getString(title.namedTitleRes, mMultiProfilePagerAdapter
+ .getCurrentListAdapter().getFilteredItem().getDisplayLabel())
: getString(title.titleRes);
}
}
@@ -576,7 +673,7 @@ public class ResolverActivity extends Activity implements
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
}
- mAdapter.handlePackagesChanged();
+ mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
updateProfileViewButton();
}
@@ -609,8 +706,8 @@ public class ResolverActivity extends Activity implements
if (!isChangingConfigurations() && mPickOptionRequest != null) {
mPickOptionRequest.cancel();
}
- if (mAdapter != null) {
- mAdapter.onDestroy();
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter() != null) {
+ mMultiProfilePagerAdapter.getCurrentListAdapter().onDestroy();
}
}
@@ -660,7 +757,8 @@ public class ResolverActivity extends Activity implements
boolean enabled = false;
ResolveInfo ri = null;
if (hasValidSelection) {
- ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
+ ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(checkedPos, filtered);
if (ri == null) {
Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
return;
@@ -701,11 +799,13 @@ public class ResolverActivity extends Activity implements
public void onButtonClick(View v) {
final int id = v.getId();
- int which = mAdapter.hasFilteredItem()
- ? mAdapter.getFilteredPosition()
- : mAdapterView.getCheckedItemPosition();
- boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
- ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
+ ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getCurrentListAdapter();
+ int which = currentListAdapter.hasFilteredItem()
+ ? currentListAdapter.getFilteredPosition()
+ : listView.getCheckedItemPosition();
+ boolean hasIndexBeenFiltered = !currentListAdapter.hasFilteredItem();
+ ResolveInfo ri = currentListAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
if (mUseLayoutForBrowsables
&& !ri.handleAllWebDataURI && id == R.id.button_always) {
showSettingsForSelected(ri);
@@ -736,7 +836,8 @@ public class ResolverActivity extends Activity implements
if (isFinishing()) {
return;
}
- ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
+ ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(which, hasIndexBeenFiltered);
if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
Toast.makeText(this, String.format(getResources().getString(
com.android.internal.R.string.activity_resolver_work_profiles_support),
@@ -745,7 +846,8 @@ public class ResolverActivity extends Activity implements
return;
}
- TargetInfo target = mAdapter.targetInfoForPosition(which, hasIndexBeenFiltered);
+ TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .targetInfoForPosition(which, hasIndexBeenFiltered);
if (target == null) {
return;
}
@@ -760,7 +862,8 @@ public class ResolverActivity extends Activity implements
MetricsLogger.action(
this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
}
- MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ MetricsLogger.action(this,
+ mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
: MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
finish();
@@ -783,10 +886,11 @@ public class ResolverActivity extends Activity implements
}
protected void onListRebuilt() {
- int count = mAdapter.getUnfilteredCount();
- if (count == 1 && mAdapter.getOtherProfile() == null) {
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
+ if (count == 1 && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
// Only one target, so we're a candidate to auto-launch!
- final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+ final TargetInfo target =
+ mMultiProfilePagerAdapter.getCurrentListAdapter().targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
finish();
@@ -798,8 +902,9 @@ public class ResolverActivity extends Activity implements
final ResolveInfo ri = target.getResolveInfo();
final Intent intent = target != null ? target.getResolvedIntent() : null;
- if (intent != null && (mSupportsAlwaysUseOption || mAdapter.hasFilteredItem())
- && mAdapter.mUnfilteredResolveList != null) {
+ if (intent != null && (mSupportsAlwaysUseOption
+ || mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem())
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredResolveList() != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
Intent filterIntent;
@@ -884,13 +989,14 @@ public class ResolverActivity extends Activity implements
}
if (filter != null) {
- final int N = mAdapter.mUnfilteredResolveList.size();
+ final int N = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getUnfilteredResolveList().size();
ComponentName[] set;
// If we don't add back in the component for forwarding the intent to a managed
// profile, the preferred activity may not be updated correctly (as the set of
// components we tell it we knew about will have changed).
final boolean needToAddBackProfileForwardingComponent =
- mAdapter.getOtherProfile() != null;
+ mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() != null;
if (!needToAddBackProfileForwardingComponent) {
set = new ComponentName[N];
} else {
@@ -899,15 +1005,18 @@ public class ResolverActivity extends Activity implements
int bestMatch = 0;
for (int i=0; i<N; i++) {
- ResolveInfo r = mAdapter.mUnfilteredResolveList.get(i).getResolveInfoAt(0);
+ ResolveInfo r = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getUnfilteredResolveList().get(i).getResolveInfoAt(0);
set[i] = new ComponentName(r.activityInfo.packageName,
r.activityInfo.name);
if (r.match > bestMatch) bestMatch = r.match;
}
if (needToAddBackProfileForwardingComponent) {
- set[N] = mAdapter.getOtherProfile().getResolvedComponentName();
- final int otherProfileMatch = mAdapter.getOtherProfile().getResolveInfo().match;
+ set[N] = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getOtherProfile().getResolvedComponentName();
+ final int otherProfileMatch = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getOtherProfile().getResolveInfo().match;
if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch;
}
@@ -946,7 +1055,8 @@ public class ResolverActivity extends Activity implements
}
} else {
try {
- mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch);
+ mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .mResolverListController.setLastChosen(intent, filter, bestMatch);
} catch (RemoteException re) {
Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
}
@@ -984,14 +1094,15 @@ public class ResolverActivity extends Activity implements
if (mProfileSwitchMessageId != -1) {
Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
}
+ UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
if (!mSafeForwardingMode) {
- if (cti.start(this, null)) {
+ if (cti.startAsUser(this, null, currentUserHandle)) {
onActivityStarted(cti);
}
return;
}
try {
- if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) {
+ if (cti.startAsCaller(this, null, currentUserHandle.getIdentifier())) {
onActivityStarted(cti);
}
} catch (RuntimeException e) {
@@ -1061,26 +1172,27 @@ public class ResolverActivity extends Activity implements
startActivity(in);
}
- public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
- Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, boolean useLayoutForBrowsables) {
-
+ @VisibleForTesting
+ protected ResolverListAdapter createResolverListAdapter(Context context,
+ List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) {
Intent startIntent = getIntent();
boolean isAudioCaptureDevice =
startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
return new ResolverListAdapter(context, payloadIntents, initialIntents, rList,
- filterLastUsed, createListController(), useLayoutForBrowsables, this,
+ filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this,
isAudioCaptureDevice);
}
@VisibleForTesting
- protected ResolverListController createListController() {
+ protected ResolverListController createListController(UserHandle userHandle) {
return new ResolverListController(
this,
mPm,
getTargetIntent(),
getReferrerPackageName(),
- mLaunchedFromUid);
+ mLaunchedFromUid,
+ userHandle);
}
/**
@@ -1088,16 +1200,17 @@ public class ResolverActivity extends Activity implements
* @return <code>true</code> if the activity is finishing and creation should halt.
*/
private boolean configureContentView() {
- if (mAdapter == null) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter() == null) {
throw new IllegalStateException("mAdapter cannot be null.");
}
- boolean rebuildCompleted = mAdapter.rebuildList();
+ boolean rebuildCompleted = mMultiProfilePagerAdapter.getCurrentListAdapter().rebuildList();
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
mLayoutId = getLayoutResource();
}
setContentView(mLayoutId);
+ mMultiProfilePagerAdapter.setupViewPager(findViewById(R.id.profile_pager));
return postRebuildList(rebuildCompleted);
}
@@ -1118,14 +1231,16 @@ public class ResolverActivity extends Activity implements
*/
final boolean postRebuildListInternal(boolean rebuildCompleted) {
- int count = mAdapter.getUnfilteredCount();
+ int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
// We only rebuild asynchronously when we have multiple elements to sort. In the case where
// we're already done, we can check if we should auto-launch immediately.
if (rebuildCompleted) {
- if (count == 1 && mAdapter.getOtherProfile() == null) {
+ if (count == 1
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
// Only one target, so we're a candidate to auto-launch!
- final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+ final TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
mPackageMonitor.unregister();
@@ -1136,37 +1251,32 @@ public class ResolverActivity extends Activity implements
}
}
- boolean isAdapterViewVisible = true;
- if (count == 0 && mAdapter.getPlaceholderCount() == 0) {
+ setupViewVisibilities(count);
+ return false;
+ }
+
+ private void setupViewVisibilities(int count) {
+ if (count == 0
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
final TextView emptyView = findViewById(R.id.empty);
emptyView.setVisibility(View.VISIBLE);
- isAdapterViewVisible = false;
+ findViewById(R.id.profile_pager).setVisibility(View.GONE);
+ } else {
+ onPrepareAdapterView(mMultiProfilePagerAdapter.getCurrentListAdapter());
}
-
- onPrepareAdapterView(mAdapter, isAdapterViewVisible);
- return false;
}
/**
* Prepare the scrollable view which consumes data in the list adapter.
* @param adapter The adapter used to provide data to item views.
- * @param isVisible True if the scrollable view should be visible; false, otherwise.
*/
- public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
- mAdapterView = findViewById(R.id.resolver_list);
- if (!isVisible) {
- mAdapterView.setVisibility(View.GONE);
- return;
- }
- mAdapterView.setVisibility(View.VISIBLE);
+ public void onPrepareAdapterView(ResolverListAdapter adapter) {
+ mMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
final boolean useHeader = adapter.hasFilteredItem();
- final ListView listView = mAdapterView instanceof ListView ? (ListView) mAdapterView : null;
-
- mAdapterView.setAdapter(mAdapter);
-
+ final ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
final ItemClickListener listener = new ItemClickListener();
- mAdapterView.setOnItemClickListener(listener);
- mAdapterView.setOnItemLongClickListener(listener);
+ listView.setOnItemClickListener(listener);
+ listView.setOnItemLongClickListener(listener);
if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
@@ -1185,7 +1295,8 @@ public class ResolverActivity extends Activity implements
* Configure the area above the app selection list (title, content preview, etc).
*/
public void setHeader() {
- if (mAdapter.getCount() == 0 && mAdapter.getPlaceholderCount() == 0) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
final TextView titleView = findViewById(R.id.title);
if (titleView != null) {
titleView.setVisibility(View.GONE);
@@ -1206,11 +1317,11 @@ public class ResolverActivity extends Activity implements
final ImageView iconView = findViewById(R.id.icon);
if (iconView != null) {
- mAdapter.loadFilteredItemIconTaskAsync(iconView);
+ mMultiProfilePagerAdapter.getCurrentListAdapter().loadFilteredItemIconTaskAsync(iconView);
}
}
- private void resetButtonBar() {
+ protected void resetButtonBar() {
if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) {
return;
}
@@ -1234,24 +1345,27 @@ public class ResolverActivity extends Activity implements
}
private void resetAlwaysOrOnceButtonBar() {
- if (useLayoutWithDefault()
- && mAdapter.getFilteredPosition() != ListView.INVALID_POSITION) {
- setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
+ int filteredPosition = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getFilteredPosition();
+ if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
+ setAlwaysButtonEnabled(true, filteredPosition, false);
mOnceButton.setEnabled(true);
return;
}
// When the items load in, if an item was already selected, enable the buttons
- if (mAdapterView != null
- && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
- setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true);
+ ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ if (currentAdapterView != null
+ && currentAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
+ setAlwaysButtonEnabled(true, currentAdapterView.getCheckedItemPosition(), true);
mOnceButton.setEnabled(true);
}
}
@Override // ResolverListCommunicator
public boolean useLayoutWithDefault() {
- return mSupportsAlwaysUseOption && mAdapter.hasFilteredItem();
+ return mSupportsAlwaysUseOption
+ && mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem();
}
/**
@@ -1275,7 +1389,7 @@ public class ResolverActivity extends Activity implements
@Override // ResolverListCommunicator
public void onHandlePackagesChanged() {
- if (mAdapter.getCount() == 0) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
// We no longer have any items... just finish the activity.
finish();
}
@@ -1350,11 +1464,14 @@ public class ResolverActivity extends Activity implements
return;
}
// If we're still loading, we can't yet enable the buttons.
- if (mAdapter.resolveInfoForPosition(position, true) == null) {
+ if (mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(position, true) == null) {
return;
}
- final int checkedPos = mAdapterView.getCheckedItemPosition();
+ ListView currentAdapterView =
+ (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ final int checkedPos = currentAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
&& (!hasValidSelection || mLastSelected != checkedPos)
@@ -1362,7 +1479,7 @@ public class ResolverActivity extends Activity implements
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
- mAdapterView.smoothScrollToPosition(checkedPos);
+ currentAdapterView.smoothScrollToPosition(checkedPos);
}
mLastSelected = checkedPos;
} else {
@@ -1380,7 +1497,8 @@ public class ResolverActivity extends Activity implements
// Header views don't count.
return false;
}
- ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true);
+ ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .resolveInfoForPosition(position, true);
showTargetDetails(ri);
return true;
}
@@ -1420,7 +1538,8 @@ public class ResolverActivity extends Activity implements
final ResolverActivity ra = (ResolverActivity) getActivity();
if (ra != null) {
- final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex());
+ final TargetInfo ti = ra.mMultiProfilePagerAdapter.getCurrentListAdapter()
+ .getItem(selections[0].getIndex());
if (ra.onTargetSelected(ti, false)) {
ra.mPickOptionRequest = null;
ra.finish();
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index bb7ca358f815..48064da7c35c 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -37,7 +37,6 @@ import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -81,7 +80,7 @@ public class ResolverListAdapter extends BaseAdapter {
// This one is the list that the Adapter will actually present.
List<DisplayResolveInfo> mDisplayList;
- List<ResolvedComponentInfo> mUnfilteredResolveList;
+ private List<ResolvedComponentInfo> mUnfilteredResolveList;
private int mLastChosenPosition = -1;
private boolean mFilterLastUsed;
@@ -162,6 +161,10 @@ public class ResolverListAdapter extends BaseAdapter {
mResolverListController.updateChooserCounts(packageName, userId, action);
}
+ List<ResolvedComponentInfo> getUnfilteredResolveList() {
+ return mUnfilteredResolveList;
+ }
+
/**
* @return true if all items in the display list are defined as browsers by
* ResolveInfo.handleAllWebDataURI
@@ -576,7 +579,7 @@ public class ResolverListAdapter extends BaseAdapter {
Drawable loadIconForResolveInfo(ResolveInfo ri) {
// Load icons based on the current process. If in work profile icons should be badged.
- return makePresentationGetter(ri).getIcon(Process.myUserHandle());
+ return makePresentationGetter(ri).getIcon(mResolverListController.getUserHandle());
}
void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) {
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index b456ca00fe2b..abd3eb2453df 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -55,6 +56,7 @@ public class ResolverListController {
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
+ private final UserHandle mUserHandle;
private AbstractResolverComparator mResolverComparator;
private boolean isComputed = false;
@@ -64,8 +66,9 @@ public class ResolverListController {
PackageManager pm,
Intent targetIntent,
String referrerPackage,
- int launchedFromUid) {
- this(context, pm, targetIntent, referrerPackage, launchedFromUid,
+ int launchedFromUid,
+ UserHandle userHandle) {
+ this(context, pm, targetIntent, referrerPackage, launchedFromUid, userHandle,
new ResolverRankerServiceResolverComparator(
context, targetIntent, referrerPackage, null));
}
@@ -76,12 +79,14 @@ public class ResolverListController {
Intent targetIntent,
String referrerPackage,
int launchedFromUid,
+ UserHandle userHandle,
AbstractResolverComparator resolverComparator) {
mContext = context;
mpm = pm;
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
+ mUserHandle = userHandle;
mResolverComparator = resolverComparator;
}
@@ -116,7 +121,8 @@ public class ResolverListController {
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
flags |= PackageManager.MATCH_INSTANT;
}
- final List<ResolveInfo> infos = mpm.queryIntentActivities(intent, flags);
+ final List<ResolveInfo> infos = mpm.queryIntentActivitiesAsUser(intent, flags,
+ mUserHandle);
if (infos != null) {
if (resolvedComponents == null) {
resolvedComponents = new ArrayList<>();
@@ -127,6 +133,10 @@ public class ResolverListController {
return resolvedComponents;
}
+ UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
@VisibleForTesting
public void addResolveListDedupe(List<ResolverActivity.ResolvedComponentInfo> into,
Intent intent,
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
new file mode 100644
index 000000000000..9e814ab5d0aa
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 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.internal.app;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.PagerAdapter;
+
+/**
+ * A {@link PagerAdapter} which describes the work and personal profile intent resolver screens.
+ */
+@VisibleForTesting
+public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
+
+ private final ResolverProfileDescriptor[] mItems;
+
+ ResolverMultiProfilePagerAdapter(Context context,
+ ResolverListAdapter adapter) {
+ super(context, /* currentPage */ 0);
+ mItems = new ResolverProfileDescriptor[] {
+ createProfileDescriptor(adapter)
+ };
+ }
+
+ ResolverMultiProfilePagerAdapter(Context context,
+ ResolverListAdapter personalAdapter,
+ ResolverListAdapter workAdapter,
+ @Profile int defaultProfile) {
+ super(context, /* currentPage */ defaultProfile);
+ mItems = new ResolverProfileDescriptor[] {
+ createProfileDescriptor(personalAdapter),
+ createProfileDescriptor(workAdapter)
+ };
+ }
+
+ private ResolverProfileDescriptor createProfileDescriptor(
+ ResolverListAdapter adapter) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final ViewGroup rootView =
+ (ViewGroup) inflater.inflate(R.layout.resolver_list_per_profile, null, false);
+ return new ResolverProfileDescriptor(rootView, adapter);
+ }
+
+ ListView getListViewForIndex(int index) {
+ return getItem(index).listView;
+ }
+
+ @Override
+ ResolverProfileDescriptor getItem(int pageIndex) {
+ return mItems[pageIndex];
+ }
+
+ @Override
+ int getItemCount() {
+ return mItems.length;
+ }
+
+ @Override
+ void setupListAdapter(int pageIndex) {
+ final ListView listView = getItem(pageIndex).listView;
+ listView.setAdapter(getItem(pageIndex).resolverListAdapter);
+ }
+
+ @Override
+ ResolverListAdapter getAdapterForIndex(int pageIndex) {
+ return mItems[pageIndex].resolverListAdapter;
+ }
+
+ @Override
+ @VisibleForTesting
+ public ResolverListAdapter getCurrentListAdapter() {
+ return getAdapterForIndex(getCurrentPage());
+ }
+
+ @Override
+ ResolverListAdapter getCurrentRootAdapter() {
+ return getCurrentListAdapter();
+ }
+
+ @Override
+ ListView getCurrentAdapterView() {
+ return getListViewForIndex(getCurrentPage());
+ }
+
+ class ResolverProfileDescriptor extends ProfileDescriptor {
+ private ResolverListAdapter resolverListAdapter;
+ final ListView listView;
+ ResolverProfileDescriptor(ViewGroup rootView, ResolverListAdapter adapter) {
+ super(rootView);
+ resolverListAdapter = adapter;
+ listView = rootView.findViewById(R.id.resolver_list);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/WrapHeightViewPager.java b/core/java/com/android/internal/app/WrapHeightViewPager.java
new file mode 100644
index 000000000000..b017bb44d751
--- /dev/null
+++ b/core/java/com/android/internal/app/WrapHeightViewPager.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.internal.app;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.internal.widget.ViewPager;
+
+/**
+ * A {@link ViewPager} which wraps around its first child's height.
+ * <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.
+ */
+public class WrapHeightViewPager extends ViewPager {
+
+ public WrapHeightViewPager(Context context) {
+ super(context);
+ }
+
+ public WrapHeightViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WrapHeightViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public WrapHeightViewPager(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);
+ if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.AT_MOST) {
+ return;
+ }
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
+ int height = getMeasuredHeight();
+ if (getChildCount() > 0) {
+ View firstChild = getChildAt(0);
+ firstChild.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
+ height = firstChild.getMeasuredHeight();
+ }
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 6807f9af3980..9f296f8f7c08 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -29,7 +29,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
- android:elevation="1dp"
+ android:elevation="0dp"
android:background="@drawable/bottomsheet_background">
<ImageView
@@ -55,16 +55,10 @@
android:layout_centerHorizontal="true"/>
</RelativeLayout>
- <com.android.internal.widget.RecyclerView
+ <com.android.internal.widget.ViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layoutManager="com.android.internal.widget.GridLayoutManager"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:scrollbars="none"
- android:elevation="1dp"
- android:nestedScrollingEnabled="true"/>
+ android:layout_height="wrap_content"/>
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml
new file mode 100644
index 000000000000..212813f10bd4
--- /dev/null
+++ b/core/res/res/layout/chooser_list_per_profile.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2019 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.
+ -->
+
+<com.android.internal.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layoutManager="com.android.internal.widget.GridLayoutManager"
+ android:id="@+id/resolver_list"
+ android:clipToPadding="false"
+ android:background="?attr/colorBackgroundFloating"
+ android:scrollbars="none"
+ android:elevation="1dp"
+ android:nestedScrollingEnabled="true"/> \ No newline at end of file
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 6e45e7a4c509..c5d891254227 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -63,25 +63,22 @@
</RelativeLayout>
<View
+ android:id="@+id/divider"
android:layout_alwaysShow="true"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <ListView
+
+ <com.android.internal.app.WrapHeightViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="@dimen/resolver_elevation"
- android:nestedScrollingEnabled="true"
- android:scrollbarStyle="outsideOverlay"
- android:scrollIndicators="top|bottom"
android:divider="?attr/dividerVertical"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
- android:dividerHeight="1dp" />
+ android:dividerHeight="1dp"/>
+
<View
android:layout_alwaysShow="true"
android:layout_width="match_parent"
@@ -89,7 +86,6 @@
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
-
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml
new file mode 100644
index 000000000000..68b991755e73
--- /dev/null
+++ b/core/res/res/layout/resolver_list_per_profile.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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.
+ -->
+<ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/resolver_list"
+ android:clipToPadding="false"
+ android:background="?attr/colorBackgroundFloating"
+ android:elevation="@dimen/resolver_elevation"
+ android:nestedScrollingEnabled="true"
+ android:scrollbarStyle="outsideOverlay"
+ android:scrollIndicators="top|bottom"
+ android:divider="?attr/dividerVertical"
+ android:footerDividersEnabled="false"
+ android:headerDividersEnabled="false"
+ android:dividerHeight="1dp" /> \ 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 dbba0b7bcc25..5b3d929d23a5 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -144,25 +144,21 @@
</LinearLayout>
<View
+ android:id="@+id/divider"
android:layout_alwaysShow="true"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <ListView
+
+ <com.android.internal.app.WrapHeightViewPager
+ android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="@dimen/resolver_elevation"
- android:nestedScrollingEnabled="true"
- android:scrollbarStyle="outsideOverlay"
- android:scrollIndicators="top|bottom"
+ android:dividerHeight="1dp"
android:divider="?attr/dividerVertical"
android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:dividerHeight="1dp" />
+ android:headerDividersEnabled="false"/>
<View
android:layout_alwaysShow="true"
android:layout_width="match_parent"
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fc1c35879a50..90343e07d4e4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -247,6 +247,7 @@
<java-symbol type="id" name="mic" />
<java-symbol type="id" name="overlay" />
<java-symbol type="id" name="app_ops" />
+ <java-symbol type="id" name="profile_pager" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1533,6 +1534,8 @@
<java-symbol type="layout" name="user_switching_dialog" />
<java-symbol type="layout" name="common_tab_settings" />
<java-symbol type="layout" name="notification_material_media_seekbar" />
+ <java-symbol type="layout" name="resolver_list_per_profile" />
+ <java-symbol type="layout" name="chooser_list_per_profile" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />