Loading AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.documentsui"> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> Loading src/com/android/documentsui/AbstractActionHandler.java +2 −2 Original line number Diff line number Diff line Loading @@ -497,7 +497,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA // First try managing the document; we expect manager to filter // based on authority, so we don't grant. Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT); manage.setData(doc.derivedUri); manage.setData(doc.getDocumentUri()); try { doc.userId.startActivityAsUser(mActivity, manage); return true; Loading Loading @@ -542,7 +542,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA protected Intent buildViewIntent(DocumentInfo doc) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(doc.derivedUri, doc.mimeType); intent.setDataAndType(doc.getDocumentUri(), doc.mimeType); // Downloads has traditionally added the WRITE permission // in the TrampolineActivity. Since this behavior is long Loading src/com/android/documentsui/base/Features.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ public interface Features { /** * Temporary compile-time feature flag to enable in-app cross-profile browsing for some intent. */ boolean CROSS_PROFILE_TABS = false; boolean CROSS_PROFILE_TABS = true; boolean isArchiveCreationEnabled(); boolean isCommandInterceptorEnabled(); Loading src/com/android/documentsui/files/QuickViewIntentBuilder.java +38 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.documentsui.files; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; import static com.android.documentsui.base.Shared.MAX_DOCS_IN_INTENT; import static com.android.documentsui.base.SharedMinimal.DEBUG; Loading @@ -41,6 +42,7 @@ import com.android.documentsui.Model; import com.android.documentsui.R; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.UserId; import com.android.documentsui.roots.RootCursorWrapper; import java.util.ArrayList; Loading Loading @@ -184,7 +186,9 @@ public final class QuickViewIntentBuilder { String mimeType; String id; String authority; UserId userId; Uri uri; boolean hasNonMatchingDocumentUser = false; // Cursor's are not guaranteed to be immutable. Hence, traverse it only once. for (int i = 0; i < siblingIds.length; i++) { Loading @@ -209,18 +213,49 @@ public final class QuickViewIntentBuilder { continue; } userId = UserId.of(getCursorInt(cursor, RootCursorWrapper.COLUMN_USER_ID)); if (!userId.equals(mDocument.userId)) { // If there is any document in the model does not have the same user as // mDocument, we will not add any siblings and the user for security reason. // Although the quick view package is trusted, the trusted quick view package may // not notice it is a cross-profile uri and may allow other app to handle this uri. if (DEBUG) { Log.d(TAG, "Skipping document from the other user. modelId: " + siblingIds[i]); } hasNonMatchingDocumentUser = true; continue; } id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY); if (UserId.CURRENT_USER.equals(userId)) { uri = DocumentsContract.buildDocumentUri(authority, id); uris.add(uri); } else { uri = userId.buildDocumentUriAsUser(authority, id); } if (id.equals(mDocument.documentId)) { uris.add(uri); documentLocation = uris.size() - 1; // Position in "uris", not in the model. if (DEBUG) { Log.d(TAG, "Found starting point for QV. " + documentLocation); } } else if (!hasNonMatchingDocumentUser) { uris.add(uri); } } if (!uris.isEmpty() && hasNonMatchingDocumentUser) { if (DEBUG) { Log.d(TAG, "Remove all other uris except the document uri"); } Uri documentUri = uris.get(documentLocation); uris.clear(); uris.add(documentUri); return 0; // index of the item in a singleton list is 0. } return documentLocation; Loading tests/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ android_library { "-0 .zip", "--auto-add-overlay", ], min_sdk_version : "29", target_sdk_version : "29", } android_test { Loading Loading @@ -95,4 +98,6 @@ android_test { certificate: "platform", instrumentation_for: "DocumentsUI", min_sdk_version : "29", target_sdk_version : "29", } Loading
AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.documentsui"> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> Loading
src/com/android/documentsui/AbstractActionHandler.java +2 −2 Original line number Diff line number Diff line Loading @@ -497,7 +497,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA // First try managing the document; we expect manager to filter // based on authority, so we don't grant. Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT); manage.setData(doc.derivedUri); manage.setData(doc.getDocumentUri()); try { doc.userId.startActivityAsUser(mActivity, manage); return true; Loading Loading @@ -542,7 +542,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA protected Intent buildViewIntent(DocumentInfo doc) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(doc.derivedUri, doc.mimeType); intent.setDataAndType(doc.getDocumentUri(), doc.mimeType); // Downloads has traditionally added the WRITE permission // in the TrampolineActivity. Since this behavior is long Loading
src/com/android/documentsui/base/Features.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ public interface Features { /** * Temporary compile-time feature flag to enable in-app cross-profile browsing for some intent. */ boolean CROSS_PROFILE_TABS = false; boolean CROSS_PROFILE_TABS = true; boolean isArchiveCreationEnabled(); boolean isCommandInterceptorEnabled(); Loading
src/com/android/documentsui/files/QuickViewIntentBuilder.java +38 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.documentsui.files; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; import static com.android.documentsui.base.Shared.MAX_DOCS_IN_INTENT; import static com.android.documentsui.base.SharedMinimal.DEBUG; Loading @@ -41,6 +42,7 @@ import com.android.documentsui.Model; import com.android.documentsui.R; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.UserId; import com.android.documentsui.roots.RootCursorWrapper; import java.util.ArrayList; Loading Loading @@ -184,7 +186,9 @@ public final class QuickViewIntentBuilder { String mimeType; String id; String authority; UserId userId; Uri uri; boolean hasNonMatchingDocumentUser = false; // Cursor's are not guaranteed to be immutable. Hence, traverse it only once. for (int i = 0; i < siblingIds.length; i++) { Loading @@ -209,18 +213,49 @@ public final class QuickViewIntentBuilder { continue; } userId = UserId.of(getCursorInt(cursor, RootCursorWrapper.COLUMN_USER_ID)); if (!userId.equals(mDocument.userId)) { // If there is any document in the model does not have the same user as // mDocument, we will not add any siblings and the user for security reason. // Although the quick view package is trusted, the trusted quick view package may // not notice it is a cross-profile uri and may allow other app to handle this uri. if (DEBUG) { Log.d(TAG, "Skipping document from the other user. modelId: " + siblingIds[i]); } hasNonMatchingDocumentUser = true; continue; } id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY); if (UserId.CURRENT_USER.equals(userId)) { uri = DocumentsContract.buildDocumentUri(authority, id); uris.add(uri); } else { uri = userId.buildDocumentUriAsUser(authority, id); } if (id.equals(mDocument.documentId)) { uris.add(uri); documentLocation = uris.size() - 1; // Position in "uris", not in the model. if (DEBUG) { Log.d(TAG, "Found starting point for QV. " + documentLocation); } } else if (!hasNonMatchingDocumentUser) { uris.add(uri); } } if (!uris.isEmpty() && hasNonMatchingDocumentUser) { if (DEBUG) { Log.d(TAG, "Remove all other uris except the document uri"); } Uri documentUri = uris.get(documentLocation); uris.clear(); uris.add(documentUri); return 0; // index of the item in a singleton list is 0. } return documentLocation; Loading
tests/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ android_library { "-0 .zip", "--auto-add-overlay", ], min_sdk_version : "29", target_sdk_version : "29", } android_test { Loading Loading @@ -95,4 +98,6 @@ android_test { certificate: "platform", instrumentation_for: "DocumentsUI", min_sdk_version : "29", target_sdk_version : "29", }