Loading src/com/android/documentsui/BaseActivity.java +2 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ public abstract class BaseActivity protected Injector<?> mInjector; protected ProvidersCache mProviders; protected UserIdManager mUserIdManager; protected DocumentsAccess mDocs; protected DrawerController mDrawer; Loading Loading @@ -152,6 +153,7 @@ public abstract class BaseActivity mDrawer = DrawerController.create(this, mInjector.config); Metrics.logActivityLaunch(mState, intent); mUserIdManager = DocumentsApplication.getUserIdManager(this); mProviders = DocumentsApplication.getProvidersCache(this); mDocs = DocumentsAccess.create(this); Loading src/com/android/documentsui/DocumentsApplication.java +10 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.text.format.DateUtils; import android.util.Log; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.UserId; import com.android.documentsui.clipping.ClipStorage; import com.android.documentsui.clipping.ClipStore; import com.android.documentsui.clipping.DocumentClipper; Loading @@ -48,6 +49,7 @@ public class DocumentsApplication extends Application { private ClipStorage mClipStore; private DocumentClipper mClipper; private DragAndDropManager mDragAndDropManager; private UserIdManager mUserIdManager; private Lookup<String, String> mFileTypeLookup; public static ProvidersCache getProvidersCache(Context context) { Loading Loading @@ -78,6 +80,10 @@ public class DocumentsApplication extends Application { return ((DocumentsApplication) context.getApplicationContext()).mClipStore; } public static UserIdManager getUserIdManager(Context context) { return ((DocumentsApplication) context.getApplicationContext()).mUserIdManager; } public static DragAndDropManager getDragAndDropManager(Context context) { return ((DocumentsApplication) context.getApplicationContext()).mDragAndDropManager; } Loading Loading @@ -105,7 +111,9 @@ public class DocumentsApplication extends Application { Log.w(TAG, "Can't obtain OverlayManager from System Service!"); } mProviders = new ProvidersCache(this); mUserIdManager = UserIdManager.create(this); mProviders = new ProvidersCache(this, mUserIdManager); mProviders.updateAsync(false); mThumbnailCache = new ThumbnailCache(memoryClassBytes / 4); Loading Loading @@ -148,7 +156,7 @@ public class DocumentsApplication extends Application { final Uri data = intent.getData(); if (data != null) { final String packageName = data.getSchemeSpecificPart(); mProviders.updatePackageAsync(packageName); mProviders.updatePackageAsync(UserId.DEFAULT_USER, packageName); } else { mProviders.updateAsync(true); } Loading src/com/android/documentsui/DrawerController.java +2 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import androidx.legacy.app.ActionBarDrawerToggle; import com.android.documentsui.base.Display; import com.android.documentsui.base.Providers; import com.android.documentsui.base.UserId; /** * A facade over the various pieces comprising "roots fragment in a Drawer". Loading Loading @@ -204,7 +205,7 @@ public abstract class DrawerController implements DrawerListener { mToggle.onDrawerOpened(drawerView); // Update the information for Storage's root DocumentsApplication.getProvidersCache(drawerView.getContext()).updateAuthorityAsync( Providers.AUTHORITY_STORAGE); UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE); } @Override Loading src/com/android/documentsui/UserIdManager.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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; } } } src/com/android/documentsui/UserPackage.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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 com.android.documentsui.base.UserId; import java.util.Objects; /** * Data class storing a user id and a package name. */ public class UserPackage { final UserId userId; final String packageName; public UserPackage(UserId userId, String packageName) { this.userId = checkNotNull(userId); this.packageName = checkNotNull(packageName); } @Override public boolean equals(Object o) { if (o == null) { return false; } if (this == o) { return true; } if (o instanceof UserPackage) { UserPackage other = (UserPackage) o; return Objects.equals(userId, other.userId) && Objects.equals(packageName, other.packageName); } return false; } @Override public int hashCode() { return Objects.hash(userId, packageName); } } Loading
src/com/android/documentsui/BaseActivity.java +2 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ public abstract class BaseActivity protected Injector<?> mInjector; protected ProvidersCache mProviders; protected UserIdManager mUserIdManager; protected DocumentsAccess mDocs; protected DrawerController mDrawer; Loading Loading @@ -152,6 +153,7 @@ public abstract class BaseActivity mDrawer = DrawerController.create(this, mInjector.config); Metrics.logActivityLaunch(mState, intent); mUserIdManager = DocumentsApplication.getUserIdManager(this); mProviders = DocumentsApplication.getProvidersCache(this); mDocs = DocumentsAccess.create(this); Loading
src/com/android/documentsui/DocumentsApplication.java +10 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.text.format.DateUtils; import android.util.Log; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.UserId; import com.android.documentsui.clipping.ClipStorage; import com.android.documentsui.clipping.ClipStore; import com.android.documentsui.clipping.DocumentClipper; Loading @@ -48,6 +49,7 @@ public class DocumentsApplication extends Application { private ClipStorage mClipStore; private DocumentClipper mClipper; private DragAndDropManager mDragAndDropManager; private UserIdManager mUserIdManager; private Lookup<String, String> mFileTypeLookup; public static ProvidersCache getProvidersCache(Context context) { Loading Loading @@ -78,6 +80,10 @@ public class DocumentsApplication extends Application { return ((DocumentsApplication) context.getApplicationContext()).mClipStore; } public static UserIdManager getUserIdManager(Context context) { return ((DocumentsApplication) context.getApplicationContext()).mUserIdManager; } public static DragAndDropManager getDragAndDropManager(Context context) { return ((DocumentsApplication) context.getApplicationContext()).mDragAndDropManager; } Loading Loading @@ -105,7 +111,9 @@ public class DocumentsApplication extends Application { Log.w(TAG, "Can't obtain OverlayManager from System Service!"); } mProviders = new ProvidersCache(this); mUserIdManager = UserIdManager.create(this); mProviders = new ProvidersCache(this, mUserIdManager); mProviders.updateAsync(false); mThumbnailCache = new ThumbnailCache(memoryClassBytes / 4); Loading Loading @@ -148,7 +156,7 @@ public class DocumentsApplication extends Application { final Uri data = intent.getData(); if (data != null) { final String packageName = data.getSchemeSpecificPart(); mProviders.updatePackageAsync(packageName); mProviders.updatePackageAsync(UserId.DEFAULT_USER, packageName); } else { mProviders.updateAsync(true); } Loading
src/com/android/documentsui/DrawerController.java +2 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import androidx.legacy.app.ActionBarDrawerToggle; import com.android.documentsui.base.Display; import com.android.documentsui.base.Providers; import com.android.documentsui.base.UserId; /** * A facade over the various pieces comprising "roots fragment in a Drawer". Loading Loading @@ -204,7 +205,7 @@ public abstract class DrawerController implements DrawerListener { mToggle.onDrawerOpened(drawerView); // Update the information for Storage's root DocumentsApplication.getProvidersCache(drawerView.getContext()).updateAuthorityAsync( Providers.AUTHORITY_STORAGE); UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE); } @Override Loading
src/com/android/documentsui/UserIdManager.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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; } } }
src/com/android/documentsui/UserPackage.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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 com.android.documentsui.base.UserId; import java.util.Objects; /** * Data class storing a user id and a package name. */ public class UserPackage { final UserId userId; final String packageName; public UserPackage(UserId userId, String packageName) { this.userId = checkNotNull(userId); this.packageName = checkNotNull(packageName); } @Override public boolean equals(Object o) { if (o == null) { return false; } if (this == o) { return true; } if (o instanceof UserPackage) { UserPackage other = (UserPackage) o; return Objects.equals(userId, other.userId) && Objects.equals(packageName, other.packageName); } return false; } @Override public int hashCode() { return Objects.hash(userId, packageName); } }