Fetch roots from all users and filter them by action

If we enable the compile-time feature flag and open pick activity,
we can see "duplicate" roots on a device with managed profiles.
Those roots will navigate to the directory of the respective user.

Bug: 148264331
Test: atest DocumentsUIGoogleTests:com.android.documentsui.UserIdManagerTest
Test: atest DocumentsUIGoogleTests
Test: manual

Change-Id: Ie2d87009e96d6ffd2c634cb10945239de1d96720
diff --git a/src/com/android/documentsui/UserIdManager.java b/src/com/android/documentsui/UserIdManager.java
new file mode 100644
index 0000000..d489712
--- /dev/null
+++ b/src/com/android/documentsui/UserIdManager.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 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.documentsui;
+
+import static androidx.core.util.Preconditions.checkNotNull;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
+
+import com.android.documentsui.base.UserId;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Interface to query user ids.
+ */
+public interface UserIdManager {
+
+    /**
+     * Returns the {@UserId} of each profile which should be queried for documents. This
+     * will always include {@link UserId#CURRENT_USER}.
+     */
+    List<UserId> getUserIds();
+
+    /**
+     * Creates an implementation of {@link UserIdManager}.
+     */
+    static UserIdManager create(Context context) {
+        return new RuntimeUserIdManager(context);
+    }
+
+    /**
+     * Implementation of {@link UserIdManager}.
+     */
+    final class RuntimeUserIdManager implements UserIdManager {
+
+        private static final String TAG = "UserIdManager";
+
+        private static final boolean ENABLE_MULTI_PROFILES = false; // compile-time feature flag
+
+        private final Context mContext;
+        private final UserId mCurrentUser;
+        private final boolean mIsDeviceSupported;
+
+        private RuntimeUserIdManager(Context context) {
+            this(context, UserId.CURRENT_USER,
+                    ENABLE_MULTI_PROFILES && isDeviceSupported(context));
+        }
+
+        @VisibleForTesting
+        RuntimeUserIdManager(Context context, UserId currentUser, boolean isDeviceSupported) {
+            mContext = context.getApplicationContext();
+            mCurrentUser = checkNotNull(currentUser);
+            mIsDeviceSupported = isDeviceSupported;
+        }
+
+        @Override
+        public List<UserId> getUserIds() {
+            final List<UserId> result = new ArrayList<>();
+            result.add(mCurrentUser);
+
+            // If the feature is disabled, return a list just containing the current user.
+            if (!mIsDeviceSupported) {
+                return result;
+            }
+
+            UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            if (userManager == null) {
+                Log.e(TAG, "cannot obtain user manager");
+                return result;
+            }
+
+            final List<UserHandle> userProfiles = userManager.getUserProfiles();
+            if (userProfiles.size() < 2) {
+                return result;
+            }
+
+            UserId systemUser = null;
+            UserId managedUser = null;
+            for (UserHandle userHandle : userProfiles) {
+                if (userHandle.isSystem()) {
+                    systemUser = UserId.of(userHandle);
+                    continue;
+                }
+                if (managedUser == null
+                        && userManager.isManagedProfile(userHandle.getIdentifier())) {
+                    managedUser = UserId.of(userHandle);
+                }
+            }
+
+            if (mCurrentUser.isSystem()) {
+                // 1. If the current user is system (personal), add the managed user.
+                if (managedUser != null) {
+                    result.add(managedUser);
+                }
+            } else if (mCurrentUser.isManagedProfile(userManager)) {
+                // 2. If the current user is a managed user, add the personal user.
+                // Since we don't have MANAGED_USERS permission to get the parent user, we will
+                // treat the system as personal although the system can theoretically in the profile
+                // group but not being the parent user(personal) of the managed user.
+                if (systemUser != null) {
+                    result.add(0, systemUser);
+                }
+            } else {
+                // 3. If we cannot resolve the users properly, we will disable the cross-profile
+                // feature by returning just the current user.
+                if (DEBUG) {
+                    Log.w(TAG, "The current user " + UserId.CURRENT_USER
+                            + " is neither system nor managed user. has system user: "
+                            + (systemUser != null));
+                }
+            }
+            return result;
+        }
+
+        private static boolean isDeviceSupported(Context context) {
+            // The feature requires Android R DocumentsContract APIs and INTERACT_ACROSS_USERS
+            // permission.
+            return (BuildCompat.isAtLeastR()
+                    || (Build.VERSION.CODENAME.equals("REL") && Build.VERSION.SDK_INT >= 30))
+                    && context.checkSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+                    == PackageManager.PERMISSION_GRANTED;
+        }
+    }
+}