Merge "DocsUI to support other intent action for file picking" into rvc-dev am: 8242882a75
Change-Id: I3d4432463d152d47d07545848499c959695eb5b5
diff --git a/src/com/android/documentsui/dirlist/Message.java b/src/com/android/documentsui/dirlist/Message.java
index 0965ae4..4fc7c49 100644
--- a/src/com/android/documentsui/dirlist/Message.java
+++ b/src/com/android/documentsui/dirlist/Message.java
@@ -143,6 +143,7 @@
update(null, mEnv.getModel().info, null,
mEnv.getContext().getDrawable(R.drawable.ic_dialog_info));
} else if (mEnv.getDisplayState().action == State.ACTION_OPEN_TREE
+ && mEnv.getDisplayState().stack.peek() != null
&& mEnv.getDisplayState().stack.peek().isBlockedFromTree()
&& mEnv.getDisplayState().restrictScopeStorage) {
updateBlockFromTreeMessage();
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index f1a58eb..084835b 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -171,7 +171,8 @@
mDrawer,
mInjector.searchManager::onSearchBarClicked);
- RootsFragment.show(getSupportFragmentManager(), null);
+ RootsFragment.show(getSupportFragmentManager(), /* includeApps= */ false,
+ /* intent= */ null);
final Intent intent = getIntent();
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index add9643..9bc337f 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -23,8 +23,6 @@
import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.Uri;
@@ -212,23 +210,23 @@
saveContainer.setBackgroundColor(Color.TRANSPARENT);
}
- if (mState.action == ACTION_GET_CONTENT) {
- final Intent moreApps = new Intent(intent);
- moreApps.setComponent(null);
- moreApps.setPackage(null);
- for (ResolveInfo info : getPackageManager().queryIntentActivities(moreApps,
- PackageManager.MATCH_DEFAULT_ONLY)) {
- if (CrossProfileUtils.isCrossProfileIntentForwarderActivity(info)) {
- mState.canShareAcrossProfile = true;
- break;
- }
- }
- RootsFragment.show(getSupportFragmentManager(), moreApps);
- } else if (mState.action == ACTION_OPEN ||
- mState.action == ACTION_CREATE ||
- mState.action == ACTION_OPEN_TREE ||
- mState.action == ACTION_PICK_COPY_DESTINATION) {
- RootsFragment.show(getSupportFragmentManager(), (Intent) null);
+ final Intent moreApps = new Intent(intent);
+ moreApps.setComponent(null);
+ moreApps.setPackage(null);
+ if (mState.supportsCrossProfile()
+ && CrossProfileUtils.getCrossProfileResolveInfo(
+ getPackageManager(), moreApps) != null) {
+ mState.canShareAcrossProfile = true;
+ }
+
+ if (mState.action == ACTION_GET_CONTENT
+ || mState.action == ACTION_OPEN
+ || mState.action == ACTION_CREATE
+ || mState.action == ACTION_OPEN_TREE
+ || mState.action == ACTION_PICK_COPY_DESTINATION) {
+ RootsFragment.show(getSupportFragmentManager(),
+ /* includeApps= */ mState.action == ACTION_GET_CONTENT,
+ /* intent= */ moreApps);
}
}
@@ -266,8 +264,9 @@
state.copyOperationSubType = intent.getIntExtra(
FileOperationService.EXTRA_OPERATION_TYPE,
FileOperationService.OPERATION_COPY);
- } else if (Features.CROSS_PROFILE_TABS && VersionUtils.isAtLeastR()
- && state.action == ACTION_GET_CONTENT) {
+ } else if (Features.CROSS_PROFILE_TABS && VersionUtils.isAtLeastR()) {
+ // We show tabs on PickActivity except copying/moving, which does not support
+ // cross-profile action.
state.supportsCrossProfile = true;
}
}
diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java
index e1d5f18..79c9f1c 100644
--- a/src/com/android/documentsui/sidebar/RootsFragment.java
+++ b/src/com/android/documentsui/sidebar/RootsFragment.java
@@ -93,6 +93,7 @@
private static final String TAG = "RootsFragment";
private static final String EXTRA_INCLUDE_APPS = "includeApps";
+ private static final String EXTRA_INCLUDE_APPS_INTENT = "includeAppsIntent";
private static final int CONTEXT_MENU_ITEM_TIMEOUT = 500;
private final OnItemClickListener mItemListener = new OnItemClickListener() {
@@ -126,9 +127,18 @@
private List<Item> mApplicationItemList;
- public static RootsFragment show(FragmentManager fm, Intent includeApps) {
+ /**
+ * Shows the {@link RootsFragment}.
+ * @param fm the FragmentManager for interacting with fragments associated with this
+ * fragment's activity
+ * @param includeApps if {@code true}, query the intent from the system and include apps in
+ * the {@RootsFragment}.
+ * @param intent the intent to query for package manager
+ */
+ public static RootsFragment show(FragmentManager fm, boolean includeApps, Intent intent) {
final Bundle args = new Bundle();
- args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
+ args.putBoolean(EXTRA_INCLUDE_APPS, includeApps);
+ args.putParcelable(EXTRA_INCLUDE_APPS_INTENT, intent);
final RootsFragment fragment = new RootsFragment();
fragment.setArguments(args);
@@ -240,7 +250,9 @@
return;
}
- Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
+ boolean shouldIncludeHandlerApp = getArguments().getBoolean(EXTRA_INCLUDE_APPS,
+ /* defaultValue= */ false);
+ Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS_INTENT);
final Intent intent = activity.getIntent();
final boolean excludeSelf =
@@ -248,12 +260,37 @@
final String excludePackage = excludeSelf ? activity.getCallingPackage() : null;
final boolean maybeShowBadge =
getBaseActivity().getDisplayState().supportsCrossProfile();
- List<Item> sortedItems = sortLoadResult(roots, excludePackage, handlerAppIntent,
+
+ // For action which supports cross profile, update the policy value in state if
+ // necessary.
+ ResolveInfo crossProfileResolveInfo = null;
+ if (state.supportsCrossProfile() && handlerAppIntent != null) {
+ crossProfileResolveInfo = CrossProfileUtils.getCrossProfileResolveInfo(
+ getContext().getPackageManager(), handlerAppIntent);
+ updateCrossProfileStateAndMaybeRefresh(
+ /* canShareAcrossProfile= */ crossProfileResolveInfo != null);
+ }
+
+ List<Item> sortedItems = sortLoadResult(
+ state,
+ roots,
+ excludePackage,
+ shouldIncludeHandlerApp ? handlerAppIntent : null,
DocumentsApplication.getProvidersCache(getContext()),
getBaseActivity().getSelectedUser(),
DocumentsApplication.getUserIdManager(getContext()).getUserIds(),
maybeShowBadge);
+ // This will be removed when feature flag is removed.
+ if (crossProfileResolveInfo != null && !Features.CROSS_PROFILE_TABS) {
+ // Add profile item if we don't support cross-profile tab.
+ sortedItems.add(new SpacerItem());
+ sortedItems.add(new ProfileItem(crossProfileResolveInfo,
+ crossProfileResolveInfo.loadLabel(
+ getContext().getPackageManager()).toString(),
+ mActionHandler));
+ }
+
// Disable drawer if only one root
activity.setRootsDrawerLocked(sortedItems.size() <= 1);
@@ -286,6 +323,20 @@
}
/**
+ * Updates the state values of whether we can share across profiles, if necessary. Also reload
+ * documents stack if the selected user is not the current user.
+ */
+ private void updateCrossProfileStateAndMaybeRefresh(boolean canShareAcrossProfile) {
+ final State state = getBaseActivity().getDisplayState();
+ if (state.canShareAcrossProfile != canShareAcrossProfile) {
+ state.canShareAcrossProfile = canShareAcrossProfile;
+ if (!UserId.CURRENT_USER.equals(getBaseActivity().getSelectedUser())) {
+ mActionHandler.loadDocumentsForCurrentStack();
+ }
+ }
+ }
+
+ /**
* If the package name of other providers or apps capable of handling the original intent
* include the preferred root source, it will have higher order than others.
* @param excludePackage Exclude activities from this given package
@@ -294,6 +345,7 @@
*/
@VisibleForTesting
List<Item> sortLoadResult(
+ State state,
Collection<RootInfo> roots,
@Nullable String excludePackage,
@Nullable Intent handlerAppIntent,
@@ -344,24 +396,50 @@
if (VERBOSE) Log.v(TAG, "Adding storage roots: " + storageProviders);
result.addAll(storageProviders);
- // Include apps that can handle this intent too.
+
+ final List<Item> rootList = new ArrayList<>();
+ final List<Item> rootListOtherUser = new ArrayList<>();
+ mApplicationItemList = new ArrayList<>();
if (handlerAppIntent != null) {
- includeHandlerApps(handlerAppIntent, excludePackage, result, otherProviders, userIds,
- maybeShowBadge);
+ includeHandlerApps(state, handlerAppIntent, excludePackage, rootList, rootListOtherUser,
+ otherProviders, userIds, maybeShowBadge);
} else {
// Only add providers
Collections.sort(otherProviders, comp);
- if (!result.isEmpty() && !otherProviders.isEmpty()) {
- result.add(new SpacerItem());
- }
- if (VERBOSE) Log.v(TAG, "Adding plain roots: " + otherProviders);
- result.addAll(otherProviders);
-
- mApplicationItemList = new ArrayList<>();
- for (Item item : otherProviders) {
+ for (RootItem item : otherProviders) {
+ if (UserId.CURRENT_USER.equals(item.userId)) {
+ rootList.add(item);
+ } else {
+ rootListOtherUser.add(item);
+ }
mApplicationItemList.add(item);
}
}
+
+
+ if (state.supportsCrossProfile() && state.canShareAcrossProfile
+ && !rootList.isEmpty() && !rootListOtherUser.isEmpty()) {
+ // Identify personal and work root list.
+ final List<Item> personalRootList;
+ final List<Item> workRootList;
+ if (UserId.CURRENT_USER.isSystem()) {
+ personalRootList = rootList;
+ workRootList = rootListOtherUser;
+ } else {
+ personalRootList = rootListOtherUser;
+ workRootList = rootList;
+ }
+
+ // Add header and list to the result
+ final List<Item> resultRootList = new ArrayList<>();
+ resultRootList.add(new HeaderItem(getString(R.string.personal_tab)));
+ resultRootList.addAll(personalRootList);
+ resultRootList.add(new HeaderItem(getString(R.string.work_tab)));
+ resultRootList.addAll(workRootList);
+ addListToResult(result, resultRootList);
+ } else {
+ addListToResult(result, rootList);
+ }
return result;
}
@@ -369,18 +447,15 @@
* Adds apps capable of handling the original intent will be included in list of roots. If
* the providers and apps are the same package name, combine them as RootAndAppItems.
*/
- private void includeHandlerApps(
- Intent handlerAppIntent, @Nullable String excludePackage, List<Item> result,
- List<RootItem> otherProviders, List<UserId> userIds, boolean maybeShowBadge) {
+ private void includeHandlerApps(State state,
+ Intent handlerAppIntent, @Nullable String excludePackage, List<Item> rootList,
+ List<Item> rootListOtherUser, List<RootItem> otherProviders, List<UserId> userIds,
+ boolean maybeShowBadge) {
if (VERBOSE) Log.v(TAG, "Adding handler apps for intent: " + handlerAppIntent);
Context context = getContext();
- final List<Item> rootList = new ArrayList<>();
- final List<Item> rootListOtherUser = new ArrayList<>();
- final List<Item> resultRootList = new ArrayList<>();
final Map<UserPackage, ResolveInfo> appsMapping = new HashMap<>();
final Map<UserPackage, Item> appItems = new HashMap<>();
- ProfileItem profileItem = null;
final String myPackageName = context.getPackageName();
for (UserId userId : userIds) {
@@ -403,13 +478,7 @@
UserPackage userPackage = new UserPackage(userId, packageName);
appsMapping.put(userPackage, info);
- // for change personal profile root.
- if (CrossProfileUtils.isCrossProfileIntentForwarderActivity(info)) {
- if (UserId.CURRENT_USER.equals(userId)) {
- profileItem = new ProfileItem(info, info.loadLabel(pm).toString(),
- mActionHandler);
- }
- } else {
+ if (!CrossProfileUtils.isCrossProfileIntentForwarderActivity(info)) {
final Item item = new AppItem(info, info.loadLabel(pm).toString(), userId,
mActionHandler);
appItems.put(userPackage, item);
@@ -419,14 +488,6 @@
}
}
- boolean canShareAcrossProfile = profileItem != null;
- if (getBaseActivity().getDisplayState().canShareAcrossProfile != canShareAcrossProfile) {
- getBaseActivity().getDisplayState().canShareAcrossProfile = canShareAcrossProfile;
- if (!UserId.CURRENT_USER.equals(getBaseActivity().getSelectedUser())) {
- mActionHandler.loadDocumentsForCurrentStack();
- }
- }
-
// If there are some providers and apps has the same package name, combine them as one item.
for (RootItem rootItem : otherProviders) {
final UserPackage userPackage = new UserPackage(rootItem.userId,
@@ -462,55 +523,14 @@
final String preferredRootPackage = getResources().getString(
R.string.preferred_root_package, "");
final ItemComparator comp = new ItemComparator(preferredRootPackage);
+ Collections.sort(rootList, comp);
+ Collections.sort(rootListOtherUser, comp);
- if (canShareAcrossProfile && Features.CROSS_PROFILE_TABS) {
- // Combine lists only if we enabled profile tab feature.
- if (!rootList.isEmpty() && !rootListOtherUser.isEmpty()) {
- // Identify personal and work root list.
- final List<Item> personalRootList;
- final List<Item> workRootList;
- if (UserId.CURRENT_USER.isSystem()) {
- personalRootList = rootList;
- workRootList = rootListOtherUser;
- } else {
- personalRootList = rootListOtherUser;
- workRootList = rootList;
- }
- Collections.sort(personalRootList, comp);
- Collections.sort(workRootList, comp);
-
- // Make sure mApplicationItemList has items from both profiles.
- final List<Item> mergeRootList =
- new ArrayList<>(rootList.size() + rootListOtherUser.size());
- mergeRootList.addAll(rootList);
- mergeRootList.addAll(rootListOtherUser);
- mApplicationItemList = mergeRootList;
-
- // Add header and list to the result
- resultRootList.add(new HeaderItem(getString(R.string.personal_tab)));
- resultRootList.addAll(personalRootList);
- resultRootList.add(new HeaderItem(getString(R.string.work_tab)));
- resultRootList.addAll(workRootList);
- } else {
- // There is no more than 1 user, we can add all lists to result without inserting
- // personal or work header.
- resultRootList.addAll(rootList);
- resultRootList.addAll(rootListOtherUser);
- Collections.sort(resultRootList, comp);
- mApplicationItemList = resultRootList;
- }
+ if (state.supportsCrossProfile() && state.canShareAcrossProfile) {
+ mApplicationItemList.addAll(rootList);
+ mApplicationItemList.addAll(rootListOtherUser);
} else {
- resultRootList.addAll(rootList);
- Collections.sort(resultRootList, comp);
- mApplicationItemList = resultRootList;
- }
- addListToResult(result, resultRootList);
-
- // This will be removed when feature flag is removed.
- if (canShareAcrossProfile && !Features.CROSS_PROFILE_TABS) {
- // Add profile item if we don't support cross-profile tab.
- result.add(new SpacerItem());
- result.add(profileItem);
+ mApplicationItemList.addAll(rootList);
}
}
diff --git a/src/com/android/documentsui/util/CrossProfileUtils.java b/src/com/android/documentsui/util/CrossProfileUtils.java
index 2e32b42..e60ffdd 100644
--- a/src/com/android/documentsui/util/CrossProfileUtils.java
+++ b/src/com/android/documentsui/util/CrossProfileUtils.java
@@ -16,8 +16,12 @@
package com.android.documentsui.util;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import androidx.annotation.Nullable;
+
/**
* A utility class for cross-profile usage.
*/
@@ -40,4 +44,20 @@
}
return false;
}
+
+ /**
+ * Returns the {@ResolveInfo} if this intent is a cross-profile intent or {@code null}
+ * otherwise.
+ */
+ @Nullable
+ public static ResolveInfo getCrossProfileResolveInfo(PackageManager packageManager,
+ Intent intent) {
+ for (ResolveInfo info : packageManager.queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY)) {
+ if (isCrossProfileIntentForwarderActivity(info)) {
+ return info;
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java b/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java
index 8a342ba..568740b 100644
--- a/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java
+++ b/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java
@@ -26,6 +26,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.documentsui.base.RootInfo;
+import com.android.documentsui.base.State;
import com.android.documentsui.base.UserId;
import com.android.documentsui.testing.TestProvidersAccess;
import com.android.documentsui.testing.TestResolveInfo;
@@ -68,7 +69,9 @@
@Test
public void testSortLoadResult_WithCorrectOrder() {
- List<Item> items = mRootsFragment.sortLoadResult(createFakeRootInfoList(),
+ List<Item> items = mRootsFragment.sortLoadResult(
+ new State(),
+ createFakeRootInfoList(),
null /* excludePackage */, null /* handlerAppIntent */, new TestProvidersAccess(),
UserId.DEFAULT_USER,
Collections.singletonList(UserId.DEFAULT_USER),