Loading src/com/android/documentsui/AbstractActionHandler.java +3 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.AnimationView; import com.android.documentsui.dirlist.AnimationView.AnimationType; import com.android.documentsui.dirlist.FocusHandler; Loading Loading @@ -591,7 +592,8 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA protected final void loadDeviceRoot() { mActivity.onRootPicked( mProviders.getRootOneshot(Providers.AUTHORITY_STORAGE, Providers.ROOT_ID_DEVICE)); mProviders.getRootOneshot(UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE, Providers.ROOT_ID_DEVICE)); } protected final void loadHomeDir() { Loading src/com/android/documentsui/LoadDocStackTask.java +7 −4 Original line number Diff line number Diff line Loading @@ -16,17 +16,19 @@ package com.android.documentsui; import androidx.annotation.Nullable; import android.app.Activity; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.util.Log; import androidx.annotation.Nullable; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.PairedTask; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.UserId; import com.android.documentsui.roots.ProvidersAccess; import java.util.List; Loading Loading @@ -97,10 +99,11 @@ public class LoadDocStackTask extends PairedTask<Activity, Uri, DocumentStack> { throw new IllegalStateException("Provider doesn't provider root id."); } RootInfo root = mProviders.getRootOneshot(authority, path.getRootId()); RootInfo root = mProviders.getRootOneshot(UserId.DEFAULT_USER, authority, path.getRootId()); if (root == null) { throw new IllegalStateException("Failed to load root for authority: " + authority + " and root ID: " + path.getRootId() + "."); throw new IllegalStateException( "Failed to load root on user " + root.userId + " for authority: " + authority + " and root ID: " + path.getRootId() + "."); } List<DocumentInfo> docs = mDocs.getDocuments(authority, path.getPath()); Loading src/com/android/documentsui/Metrics.java +2 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.files.LauncherActivity; import com.android.documentsui.picker.PickResult; import com.android.documentsui.roots.ProvidersAccess; Loading Loading @@ -340,7 +341,7 @@ public final class Metrics { context.getContentResolver(), Providers.AUTHORITY_STORAGE)) { final Path path = DocumentsContract.findDocumentPath(wrap(client), docUri); final ProvidersAccess providers = DocumentsApplication.getProvidersCache(context); final RootInfo root = providers.getRootOneshot( final RootInfo root = providers.getRootOneshot(UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE, path.getRootId()); isInternal = !root.supportsEject(); } catch (FileNotFoundException | RemoteException | RuntimeException e) { Loading src/com/android/documentsui/base/RootInfo.java +16 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { // private static final int VERSION_INIT = 1; // Not used anymore private static final int VERSION_DROP_TYPE = 2; private static final int VERSION_SEARCH_TYPE = 3; private static final int VERSION_USER_ID = 4; // The values of these constants determine the sort order of various roots in the RootsFragment. @IntDef(flag = false, value = { Loading Loading @@ -87,6 +88,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public static final int TYPE_USB = 10; public static final int TYPE_OTHER = 11; public UserId userId; public String authority; public String rootId; public int flags; Loading @@ -112,6 +114,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void reset() { userId = UserId.UNSPECIFIED_USER; authority = null; rootId = null; flags = 0; Loading @@ -133,7 +136,12 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_USER_ID: userId = UserId.read(in); case VERSION_SEARCH_TYPE: if (version < VERSION_USER_ID) { userId = UserId.CURRENT_USER; } queryArgs = DurableUtils.readNullableString(in); case VERSION_DROP_TYPE: authority = DurableUtils.readNullableString(in); Loading @@ -154,7 +162,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void write(DataOutputStream out) throws IOException { out.writeInt(VERSION_SEARCH_TYPE); out.writeInt(VERSION_USER_ID); UserId.write(out, userId); DurableUtils.writeNullableString(out, queryArgs); DurableUtils.writeNullableString(out, authority); DurableUtils.writeNullableString(out, rootId); Loading Loading @@ -191,8 +200,9 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { } }; public static RootInfo fromRootsCursor(String authority, Cursor cursor) { public static RootInfo fromRootsCursor(UserId userId, String authority, Cursor cursor) { final RootInfo root = new RootInfo(); root.userId = userId; root.authority = authority; root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID); root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS); Loading Loading @@ -430,7 +440,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { if (o instanceof RootInfo) { RootInfo other = (RootInfo) o; return Objects.equals(authority, other.authority) return Objects.equals(userId, other.userId) && Objects.equals(authority, other.authority) && Objects.equals(rootId, other.rootId); } Loading @@ -439,7 +450,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public int hashCode() { return Objects.hash(authority, rootId); return Objects.hash(userId, authority, rootId); } @Override Loading @@ -461,6 +472,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public String toString() { return "Root{" + "userId=" + userId + "authority=" + authority + ", rootId=" + rootId + ", title=" + title Loading src/com/android/documentsui/base/UserId.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.base; import static androidx.core.util.Preconditions.checkNotNull; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.os.Process; import android.os.UserHandle; import androidx.annotation.VisibleForTesting; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ProtocolException; import java.util.Objects; /** * Representation of a {@link UserHandle}. */ public final class UserId { // A unspecified user is used as when the user's value is uninitialized. e.g. rootInfo.reset() public static UserId UNSPECIFIED_USER = UserId.of(UserHandle.of(-1000)); // A current user represents the user of the app's process. It is mainly used for comparison. public static UserId CURRENT_USER = UserId.of(Process.myUserHandle()); // A default user represents the user of the app's process. It is mainly used for operation // which supports only the current user only. public static UserId DEFAULT_USER = CURRENT_USER; private static final int VERSION_INIT = 1; private final UserHandle mUserHandle; private UserId(UserHandle userHandle) { checkNotNull(userHandle); mUserHandle = userHandle; } /** * Returns a {@link UserId} for a given {@link UserHandle}. */ @VisibleForTesting static UserId of(UserHandle userHandle) { return new UserId(userHandle); } /** * Returns the given context if the user is the current user or unspecified. Otherwise, returns * an "android" package context as the user. * * @throws IllegalStateException if android package of the other user does not exist */ @VisibleForTesting Context asContext(Context context) { if (CURRENT_USER.equals(this) || isUnspecified()) { return context; } try { return context.createPackageContextAsUser("android", /* flags= */ 0, mUserHandle); } catch (PackageManager.NameNotFoundException e) { throw new IllegalStateException("android package not found."); } } /** * Return a package manager instance of this user. */ public PackageManager getPackageManager(Context context) { return asContext(context).getPackageManager(); } /** * Return a content resolver instance of this user. */ public ContentResolver getContentResolver(Context context) { return asContext(context).getContentResolver(); } private boolean isUnspecified() { return UNSPECIFIED_USER.equals(this); } @Override public String toString() { return "UserId{" + (isUnspecified() ? "UNSPECIFIED" : mUserHandle.getIdentifier()) + "}"; } @Override public boolean equals(Object o) { if (o == null) { return false; } if (this == o) { return true; } if (o instanceof UserId) { UserId other = (UserId) o; return Objects.equals(mUserHandle, other.mUserHandle); } return false; } @Override public int hashCode() { return Objects.hash(mUserHandle); } /** * Reads a {@link UserId} from an input stream. */ public static UserId read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_INIT: int userId = in.readInt(); return UserId.of(UserHandle.of(userId)); default: throw new ProtocolException("Unknown version " + version); } } /** * Writes a {@link UserId} to an output stream. */ public static void write(DataOutputStream out, UserId userId) throws IOException { out.writeInt(VERSION_INIT); out.writeInt(userId.mUserHandle.getIdentifier()); } } Loading
src/com/android/documentsui/AbstractActionHandler.java +3 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.AnimationView; import com.android.documentsui.dirlist.AnimationView.AnimationType; import com.android.documentsui.dirlist.FocusHandler; Loading Loading @@ -591,7 +592,8 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA protected final void loadDeviceRoot() { mActivity.onRootPicked( mProviders.getRootOneshot(Providers.AUTHORITY_STORAGE, Providers.ROOT_ID_DEVICE)); mProviders.getRootOneshot(UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE, Providers.ROOT_ID_DEVICE)); } protected final void loadHomeDir() { Loading
src/com/android/documentsui/LoadDocStackTask.java +7 −4 Original line number Diff line number Diff line Loading @@ -16,17 +16,19 @@ package com.android.documentsui; import androidx.annotation.Nullable; import android.app.Activity; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.util.Log; import androidx.annotation.Nullable; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.PairedTask; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.UserId; import com.android.documentsui.roots.ProvidersAccess; import java.util.List; Loading Loading @@ -97,10 +99,11 @@ public class LoadDocStackTask extends PairedTask<Activity, Uri, DocumentStack> { throw new IllegalStateException("Provider doesn't provider root id."); } RootInfo root = mProviders.getRootOneshot(authority, path.getRootId()); RootInfo root = mProviders.getRootOneshot(UserId.DEFAULT_USER, authority, path.getRootId()); if (root == null) { throw new IllegalStateException("Failed to load root for authority: " + authority + " and root ID: " + path.getRootId() + "."); throw new IllegalStateException( "Failed to load root on user " + root.userId + " for authority: " + authority + " and root ID: " + path.getRootId() + "."); } List<DocumentInfo> docs = mDocs.getDocuments(authority, path.getPath()); Loading
src/com/android/documentsui/Metrics.java +2 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.files.LauncherActivity; import com.android.documentsui.picker.PickResult; import com.android.documentsui.roots.ProvidersAccess; Loading Loading @@ -340,7 +341,7 @@ public final class Metrics { context.getContentResolver(), Providers.AUTHORITY_STORAGE)) { final Path path = DocumentsContract.findDocumentPath(wrap(client), docUri); final ProvidersAccess providers = DocumentsApplication.getProvidersCache(context); final RootInfo root = providers.getRootOneshot( final RootInfo root = providers.getRootOneshot(UserId.DEFAULT_USER, Providers.AUTHORITY_STORAGE, path.getRootId()); isInternal = !root.supportsEject(); } catch (FileNotFoundException | RemoteException | RuntimeException e) { Loading
src/com/android/documentsui/base/RootInfo.java +16 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { // private static final int VERSION_INIT = 1; // Not used anymore private static final int VERSION_DROP_TYPE = 2; private static final int VERSION_SEARCH_TYPE = 3; private static final int VERSION_USER_ID = 4; // The values of these constants determine the sort order of various roots in the RootsFragment. @IntDef(flag = false, value = { Loading Loading @@ -87,6 +88,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public static final int TYPE_USB = 10; public static final int TYPE_OTHER = 11; public UserId userId; public String authority; public String rootId; public int flags; Loading @@ -112,6 +114,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void reset() { userId = UserId.UNSPECIFIED_USER; authority = null; rootId = null; flags = 0; Loading @@ -133,7 +136,12 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { public void read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_USER_ID: userId = UserId.read(in); case VERSION_SEARCH_TYPE: if (version < VERSION_USER_ID) { userId = UserId.CURRENT_USER; } queryArgs = DurableUtils.readNullableString(in); case VERSION_DROP_TYPE: authority = DurableUtils.readNullableString(in); Loading @@ -154,7 +162,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public void write(DataOutputStream out) throws IOException { out.writeInt(VERSION_SEARCH_TYPE); out.writeInt(VERSION_USER_ID); UserId.write(out, userId); DurableUtils.writeNullableString(out, queryArgs); DurableUtils.writeNullableString(out, authority); DurableUtils.writeNullableString(out, rootId); Loading Loading @@ -191,8 +200,9 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { } }; public static RootInfo fromRootsCursor(String authority, Cursor cursor) { public static RootInfo fromRootsCursor(UserId userId, String authority, Cursor cursor) { final RootInfo root = new RootInfo(); root.userId = userId; root.authority = authority; root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID); root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS); Loading Loading @@ -430,7 +440,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { if (o instanceof RootInfo) { RootInfo other = (RootInfo) o; return Objects.equals(authority, other.authority) return Objects.equals(userId, other.userId) && Objects.equals(authority, other.authority) && Objects.equals(rootId, other.rootId); } Loading @@ -439,7 +450,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public int hashCode() { return Objects.hash(authority, rootId); return Objects.hash(userId, authority, rootId); } @Override Loading @@ -461,6 +472,7 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { @Override public String toString() { return "Root{" + "userId=" + userId + "authority=" + authority + ", rootId=" + rootId + ", title=" + title Loading
src/com/android/documentsui/base/UserId.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.base; import static androidx.core.util.Preconditions.checkNotNull; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.os.Process; import android.os.UserHandle; import androidx.annotation.VisibleForTesting; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ProtocolException; import java.util.Objects; /** * Representation of a {@link UserHandle}. */ public final class UserId { // A unspecified user is used as when the user's value is uninitialized. e.g. rootInfo.reset() public static UserId UNSPECIFIED_USER = UserId.of(UserHandle.of(-1000)); // A current user represents the user of the app's process. It is mainly used for comparison. public static UserId CURRENT_USER = UserId.of(Process.myUserHandle()); // A default user represents the user of the app's process. It is mainly used for operation // which supports only the current user only. public static UserId DEFAULT_USER = CURRENT_USER; private static final int VERSION_INIT = 1; private final UserHandle mUserHandle; private UserId(UserHandle userHandle) { checkNotNull(userHandle); mUserHandle = userHandle; } /** * Returns a {@link UserId} for a given {@link UserHandle}. */ @VisibleForTesting static UserId of(UserHandle userHandle) { return new UserId(userHandle); } /** * Returns the given context if the user is the current user or unspecified. Otherwise, returns * an "android" package context as the user. * * @throws IllegalStateException if android package of the other user does not exist */ @VisibleForTesting Context asContext(Context context) { if (CURRENT_USER.equals(this) || isUnspecified()) { return context; } try { return context.createPackageContextAsUser("android", /* flags= */ 0, mUserHandle); } catch (PackageManager.NameNotFoundException e) { throw new IllegalStateException("android package not found."); } } /** * Return a package manager instance of this user. */ public PackageManager getPackageManager(Context context) { return asContext(context).getPackageManager(); } /** * Return a content resolver instance of this user. */ public ContentResolver getContentResolver(Context context) { return asContext(context).getContentResolver(); } private boolean isUnspecified() { return UNSPECIFIED_USER.equals(this); } @Override public String toString() { return "UserId{" + (isUnspecified() ? "UNSPECIFIED" : mUserHandle.getIdentifier()) + "}"; } @Override public boolean equals(Object o) { if (o == null) { return false; } if (this == o) { return true; } if (o instanceof UserId) { UserId other = (UserId) o; return Objects.equals(mUserHandle, other.mUserHandle); } return false; } @Override public int hashCode() { return Objects.hash(mUserHandle); } /** * Reads a {@link UserId} from an input stream. */ public static UserId read(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_INIT: int userId = in.readInt(); return UserId.of(UserHandle.of(userId)); default: throw new ProtocolException("Unknown version " + version); } } /** * Writes a {@link UserId} to an output stream. */ public static void write(DataOutputStream out, UserId userId) throws IOException { out.writeInt(VERSION_INIT); out.writeInt(userId.mUserHandle.getIdentifier()); } }