Loading core/java/android/content/Context.java +9 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,7 @@ public abstract class Context { BIND_IMPORTANT, BIND_ADJUST_WITH_ACTIVITY, BIND_NOT_PERCEPTIBLE, BIND_DENY_ACTIVITY_STARTS, BIND_INCLUDE_CAPABILITIES }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -370,6 +371,14 @@ public abstract class Context { /*********** Public flags above this line ***********/ /*********** Hidden flags below this line ***********/ /** * Flag for {@link #bindService}: If binding from an app that is visible, the bound service is * allowed to start an activity from background. Add a flag so that this behavior can be opted * out. * @hide */ public static final int BIND_DENY_ACTIVITY_STARTS = 0X000004000; /** * Flag for {@link #bindService}: This flag is only intended to be used by the system to * indicate that a service binding is not considered as real package component usage and should Loading core/java/android/provider/Settings.java +7 −0 Original line number Diff line number Diff line Loading @@ -9089,6 +9089,13 @@ public final class Settings { @Readable public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; /** * Internal collection of audio device inventory items * The device item stored are {@link com.android.server.audio.AdiDeviceState} * @hide */ public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory"; /** * Indicates whether the spatial audio feature was enabled for this user. * Loading core/java/com/android/internal/content/FileSystemProvider.java +92 −76 Original line number Diff line number Diff line Loading @@ -62,14 +62,14 @@ import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayDeque; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Queue; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import java.util.regex.Pattern; /** * A helper class for {@link android.provider.DocumentsProvider} to perform file operations on local Loading @@ -87,6 +87,8 @@ public abstract class FileSystemProvider extends DocumentsProvider { DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER, DocumentsContract.QUERY_ARG_MIME_TYPES); private static final int MAX_RESULTS_NUMBER = 23; private static String joinNewline(String... args) { return TextUtils.join("\n", args); } Loading Loading @@ -373,56 +375,53 @@ public abstract class FileSystemProvider extends DocumentsProvider { } /** * This method is similar to * {@link DocumentsProvider#queryChildDocuments(String, String[], String)}. This method returns * all children documents including hidden directories/files. * * <p> * In a scoped storage world, access to "Android/data" style directories are hidden for privacy * reasons. This method may show privacy sensitive data, so its usage should only be in * restricted modes. * * @param parentDocumentId the directory to return children for. * @param projection list of {@link Document} columns to put into the * cursor. If {@code null} all supported columns should be * included. * @param sortOrder how to order the rows, formatted as an SQL * {@code ORDER BY} clause (excluding the ORDER BY itself). * Passing {@code null} will use the default sort order, which * may be unordered. This ordering is a hint that can be used to * prioritize how data is fetched from the network, but UI may * always enforce a specific ordering * @throws FileNotFoundException when parent document doesn't exist or query fails * WARNING: this method should really be {@code final}, but for the backward compatibility it's * not; new classes that extend {@link FileSystemProvider} should override * {@link #queryChildDocuments(String, String[], String, boolean)}, not this method. */ protected Cursor queryChildDocumentsShowAll( String parentDocumentId, String[] projection, String sortOrder) @Override public Cursor queryChildDocuments(String documentId, String[] projection, String sortOrder) throws FileNotFoundException { return queryChildDocuments(parentDocumentId, projection, sortOrder, File -> true); return queryChildDocuments(documentId, projection, sortOrder, /* includeHidden */ false); } /** * This method is similar to {@link #queryChildDocuments(String, String[], String)}, however, it * could return <b>all</b> content of the directory, <b>including restricted (hidden) * directories and files</b>. * <p> * In the scoped storage world, some directories and files (e.g. {@code Android/data/} and * {@code Android/obb/} on the external storage) are hidden for privacy reasons. * Hence, this method may reveal privacy-sensitive data, thus should be used with extra care. */ @Override public Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { // Access to some directories is hidden for privacy reasons. return queryChildDocuments(parentDocumentId, projection, sortOrder, this::shouldShow); public final Cursor queryChildDocumentsForManage(String documentId, String[] projection, String sortOrder) throws FileNotFoundException { return queryChildDocuments(documentId, projection, sortOrder, /* includeHidden */ true); } private Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder, @NonNull Predicate<File> filter) throws FileNotFoundException { final File parent = getFileForDocId(parentDocumentId); protected Cursor queryChildDocuments(String documentId, String[] projection, String sortOrder, boolean includeHidden) throws FileNotFoundException { final File parent = getFileForDocId(documentId); final MatrixCursor result = new DirectoryCursor( resolveProjection(projection), parentDocumentId, parent); if (parent.isDirectory()) { for (File file : FileUtils.listFilesOrEmpty(parent)) { if (filter.test(file)) { includeFile(result, null, file); resolveProjection(projection), documentId, parent); if (!parent.isDirectory()) { Log.w(TAG, '"' + documentId + "\" is not a directory"); return result; } if (!includeHidden && shouldHideDocument(documentId)) { Log.w(TAG, "Queried directory \"" + documentId + "\" is hidden"); return result; } } else { Log.w(TAG, "parentDocumentId '" + parentDocumentId + "' is not Directory"); for (File file : FileUtils.listFilesOrEmpty(parent)) { if (!includeHidden && shouldHideDocument(file)) continue; includeFile(result, null, file); } return result; } Loading @@ -444,23 +443,29 @@ public abstract class FileSystemProvider extends DocumentsProvider { * * @see ContentResolver#EXTRA_HONORED_ARGS */ protected final Cursor querySearchDocuments( File folder, String[] projection, Set<String> exclusion, Bundle queryArgs) throws FileNotFoundException { protected final Cursor querySearchDocuments(File folder, String[] projection, Set<String> exclusion, Bundle queryArgs) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveProjection(projection)); final LinkedList<File> pending = new LinkedList<>(); pending.add(folder); while (!pending.isEmpty() && result.getCount() < 24) { final File file = pending.removeFirst(); if (shouldHide(file)) continue; // We'll be a running a BFS here. final Queue<File> pending = new ArrayDeque<>(); pending.offer(folder); while (!pending.isEmpty() && result.getCount() < MAX_RESULTS_NUMBER) { final File file = pending.poll(); // Skip hidden documents (both files and directories) if (shouldHideDocument(file)) continue; if (file.isDirectory()) { for (File child : FileUtils.listFilesOrEmpty(file)) { pending.add(child); pending.offer(child); } } if (!exclusion.contains(file.getAbsolutePath()) && matchSearchQueryArguments(file, queryArgs)) { if (exclusion.contains(file.getAbsolutePath())) continue; if (matchSearchQueryArguments(file, queryArgs)) { includeFile(result, null, file); } } Loading Loading @@ -604,26 +609,23 @@ public abstract class FileSystemProvider extends DocumentsProvider { final int flagIndex = ArrayUtils.indexOf(columns, Document.COLUMN_FLAGS); if (flagIndex != -1) { final boolean isDir = mimeType.equals(Document.MIME_TYPE_DIR); int flags = 0; if (file.canWrite()) { if (mimeType.equals(Document.MIME_TYPE_DIR)) { flags |= Document.FLAG_DIR_SUPPORTS_CREATE; flags |= Document.FLAG_SUPPORTS_DELETE; flags |= Document.FLAG_SUPPORTS_RENAME; flags |= Document.FLAG_SUPPORTS_MOVE; if (shouldBlockFromTree(docId)) { flags |= Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; } if (isDir) { flags |= Document.FLAG_DIR_SUPPORTS_CREATE; } else { flags |= Document.FLAG_SUPPORTS_WRITE; flags |= Document.FLAG_SUPPORTS_DELETE; flags |= Document.FLAG_SUPPORTS_RENAME; flags |= Document.FLAG_SUPPORTS_MOVE; } } if (isDir && shouldBlockDirectoryFromTree(docId)) { flags |= Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; } if (mimeType.startsWith("image/")) { flags |= Document.FLAG_SUPPORTS_THUMBNAIL; } Loading Loading @@ -656,22 +658,36 @@ public abstract class FileSystemProvider extends DocumentsProvider { return row; } private static final Pattern PATTERN_HIDDEN_PATH = Pattern.compile( "(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|obb|sandbox)$"); /** * In a scoped storage world, access to "Android/data" style directories are * hidden for privacy reasons. * Some providers may want to restrict access to certain directories and files, * e.g. <i>"Android/data"</i> and <i>"Android/obb"</i> on the shared storage for * privacy reasons. * Such providers should override this method. */ protected boolean shouldHide(@NonNull File file) { return (PATTERN_HIDDEN_PATH.matcher(file.getAbsolutePath()).matches()); protected boolean shouldHideDocument(@NonNull String documentId) throws FileNotFoundException { return false; } private boolean shouldShow(@NonNull File file) { return !shouldHide(file); /** * A variant of the {@link #shouldHideDocument(String)} that takes a {@link File} instead of * a {@link String} {@code documentId}. * * @see #shouldHideDocument(String) */ protected final boolean shouldHideDocument(@NonNull File document) throws FileNotFoundException { return shouldHideDocument(getDocIdForFile(document)); } protected boolean shouldBlockFromTree(@NonNull String docId) { /** * @return if the directory that should be blocked from being selected when the user launches * an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} intent. * * @see Document#FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE */ protected boolean shouldBlockDirectoryFromTree(@NonNull String documentId) throws FileNotFoundException { return false; } Loading core/proto/android/server/activitymanagerservice.proto +1 −0 Original line number Diff line number Diff line Loading @@ -524,6 +524,7 @@ message ConnectionRecordProto { DEAD = 15; NOT_PERCEPTIBLE = 16; INCLUDE_CAPABILITIES = 17; DENY_ACTIVITY_STARTS = 18; } repeated Flag flags = 3; optional string service_name = 4; Loading media/java/android/media/AudioDeviceAttributes.java +22 −2 Original line number Diff line number Diff line Loading @@ -64,8 +64,7 @@ public final class AudioDeviceAttributes implements Parcelable { /** * The unique address of the device. Some devices don't have addresses, only an empty string. */ private final @NonNull String mAddress; private @NonNull String mAddress; /** * Is input or output device */ Loading Loading @@ -133,6 +132,18 @@ public final class AudioDeviceAttributes implements Parcelable { mNativeType = nativeType; } /** * @hide * Copy Constructor. * @param ada the copied AudioDeviceAttributes */ public AudioDeviceAttributes(AudioDeviceAttributes ada) { mRole = ada.getRole(); mType = ada.getType(); mAddress = ada.getAddress(); mNativeType = ada.getInternalType(); } /** * @hide * Returns the role of a device Loading Loading @@ -163,6 +174,15 @@ public final class AudioDeviceAttributes implements Parcelable { return mAddress; } /** * @hide * Sets the device address. Only used by audio service. */ public void setAddress(@NonNull String address) { Objects.requireNonNull(address); mAddress = address; } /** * @hide * Returns the internal device type of a device Loading Loading
core/java/android/content/Context.java +9 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,7 @@ public abstract class Context { BIND_IMPORTANT, BIND_ADJUST_WITH_ACTIVITY, BIND_NOT_PERCEPTIBLE, BIND_DENY_ACTIVITY_STARTS, BIND_INCLUDE_CAPABILITIES }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -370,6 +371,14 @@ public abstract class Context { /*********** Public flags above this line ***********/ /*********** Hidden flags below this line ***********/ /** * Flag for {@link #bindService}: If binding from an app that is visible, the bound service is * allowed to start an activity from background. Add a flag so that this behavior can be opted * out. * @hide */ public static final int BIND_DENY_ACTIVITY_STARTS = 0X000004000; /** * Flag for {@link #bindService}: This flag is only intended to be used by the system to * indicate that a service binding is not considered as real package component usage and should Loading
core/java/android/provider/Settings.java +7 −0 Original line number Diff line number Diff line Loading @@ -9089,6 +9089,13 @@ public final class Settings { @Readable public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; /** * Internal collection of audio device inventory items * The device item stored are {@link com.android.server.audio.AdiDeviceState} * @hide */ public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory"; /** * Indicates whether the spatial audio feature was enabled for this user. * Loading
core/java/com/android/internal/content/FileSystemProvider.java +92 −76 Original line number Diff line number Diff line Loading @@ -62,14 +62,14 @@ import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayDeque; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Queue; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import java.util.regex.Pattern; /** * A helper class for {@link android.provider.DocumentsProvider} to perform file operations on local Loading @@ -87,6 +87,8 @@ public abstract class FileSystemProvider extends DocumentsProvider { DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER, DocumentsContract.QUERY_ARG_MIME_TYPES); private static final int MAX_RESULTS_NUMBER = 23; private static String joinNewline(String... args) { return TextUtils.join("\n", args); } Loading Loading @@ -373,56 +375,53 @@ public abstract class FileSystemProvider extends DocumentsProvider { } /** * This method is similar to * {@link DocumentsProvider#queryChildDocuments(String, String[], String)}. This method returns * all children documents including hidden directories/files. * * <p> * In a scoped storage world, access to "Android/data" style directories are hidden for privacy * reasons. This method may show privacy sensitive data, so its usage should only be in * restricted modes. * * @param parentDocumentId the directory to return children for. * @param projection list of {@link Document} columns to put into the * cursor. If {@code null} all supported columns should be * included. * @param sortOrder how to order the rows, formatted as an SQL * {@code ORDER BY} clause (excluding the ORDER BY itself). * Passing {@code null} will use the default sort order, which * may be unordered. This ordering is a hint that can be used to * prioritize how data is fetched from the network, but UI may * always enforce a specific ordering * @throws FileNotFoundException when parent document doesn't exist or query fails * WARNING: this method should really be {@code final}, but for the backward compatibility it's * not; new classes that extend {@link FileSystemProvider} should override * {@link #queryChildDocuments(String, String[], String, boolean)}, not this method. */ protected Cursor queryChildDocumentsShowAll( String parentDocumentId, String[] projection, String sortOrder) @Override public Cursor queryChildDocuments(String documentId, String[] projection, String sortOrder) throws FileNotFoundException { return queryChildDocuments(parentDocumentId, projection, sortOrder, File -> true); return queryChildDocuments(documentId, projection, sortOrder, /* includeHidden */ false); } /** * This method is similar to {@link #queryChildDocuments(String, String[], String)}, however, it * could return <b>all</b> content of the directory, <b>including restricted (hidden) * directories and files</b>. * <p> * In the scoped storage world, some directories and files (e.g. {@code Android/data/} and * {@code Android/obb/} on the external storage) are hidden for privacy reasons. * Hence, this method may reveal privacy-sensitive data, thus should be used with extra care. */ @Override public Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { // Access to some directories is hidden for privacy reasons. return queryChildDocuments(parentDocumentId, projection, sortOrder, this::shouldShow); public final Cursor queryChildDocumentsForManage(String documentId, String[] projection, String sortOrder) throws FileNotFoundException { return queryChildDocuments(documentId, projection, sortOrder, /* includeHidden */ true); } private Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder, @NonNull Predicate<File> filter) throws FileNotFoundException { final File parent = getFileForDocId(parentDocumentId); protected Cursor queryChildDocuments(String documentId, String[] projection, String sortOrder, boolean includeHidden) throws FileNotFoundException { final File parent = getFileForDocId(documentId); final MatrixCursor result = new DirectoryCursor( resolveProjection(projection), parentDocumentId, parent); if (parent.isDirectory()) { for (File file : FileUtils.listFilesOrEmpty(parent)) { if (filter.test(file)) { includeFile(result, null, file); resolveProjection(projection), documentId, parent); if (!parent.isDirectory()) { Log.w(TAG, '"' + documentId + "\" is not a directory"); return result; } if (!includeHidden && shouldHideDocument(documentId)) { Log.w(TAG, "Queried directory \"" + documentId + "\" is hidden"); return result; } } else { Log.w(TAG, "parentDocumentId '" + parentDocumentId + "' is not Directory"); for (File file : FileUtils.listFilesOrEmpty(parent)) { if (!includeHidden && shouldHideDocument(file)) continue; includeFile(result, null, file); } return result; } Loading @@ -444,23 +443,29 @@ public abstract class FileSystemProvider extends DocumentsProvider { * * @see ContentResolver#EXTRA_HONORED_ARGS */ protected final Cursor querySearchDocuments( File folder, String[] projection, Set<String> exclusion, Bundle queryArgs) throws FileNotFoundException { protected final Cursor querySearchDocuments(File folder, String[] projection, Set<String> exclusion, Bundle queryArgs) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveProjection(projection)); final LinkedList<File> pending = new LinkedList<>(); pending.add(folder); while (!pending.isEmpty() && result.getCount() < 24) { final File file = pending.removeFirst(); if (shouldHide(file)) continue; // We'll be a running a BFS here. final Queue<File> pending = new ArrayDeque<>(); pending.offer(folder); while (!pending.isEmpty() && result.getCount() < MAX_RESULTS_NUMBER) { final File file = pending.poll(); // Skip hidden documents (both files and directories) if (shouldHideDocument(file)) continue; if (file.isDirectory()) { for (File child : FileUtils.listFilesOrEmpty(file)) { pending.add(child); pending.offer(child); } } if (!exclusion.contains(file.getAbsolutePath()) && matchSearchQueryArguments(file, queryArgs)) { if (exclusion.contains(file.getAbsolutePath())) continue; if (matchSearchQueryArguments(file, queryArgs)) { includeFile(result, null, file); } } Loading Loading @@ -604,26 +609,23 @@ public abstract class FileSystemProvider extends DocumentsProvider { final int flagIndex = ArrayUtils.indexOf(columns, Document.COLUMN_FLAGS); if (flagIndex != -1) { final boolean isDir = mimeType.equals(Document.MIME_TYPE_DIR); int flags = 0; if (file.canWrite()) { if (mimeType.equals(Document.MIME_TYPE_DIR)) { flags |= Document.FLAG_DIR_SUPPORTS_CREATE; flags |= Document.FLAG_SUPPORTS_DELETE; flags |= Document.FLAG_SUPPORTS_RENAME; flags |= Document.FLAG_SUPPORTS_MOVE; if (shouldBlockFromTree(docId)) { flags |= Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; } if (isDir) { flags |= Document.FLAG_DIR_SUPPORTS_CREATE; } else { flags |= Document.FLAG_SUPPORTS_WRITE; flags |= Document.FLAG_SUPPORTS_DELETE; flags |= Document.FLAG_SUPPORTS_RENAME; flags |= Document.FLAG_SUPPORTS_MOVE; } } if (isDir && shouldBlockDirectoryFromTree(docId)) { flags |= Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; } if (mimeType.startsWith("image/")) { flags |= Document.FLAG_SUPPORTS_THUMBNAIL; } Loading Loading @@ -656,22 +658,36 @@ public abstract class FileSystemProvider extends DocumentsProvider { return row; } private static final Pattern PATTERN_HIDDEN_PATH = Pattern.compile( "(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|obb|sandbox)$"); /** * In a scoped storage world, access to "Android/data" style directories are * hidden for privacy reasons. * Some providers may want to restrict access to certain directories and files, * e.g. <i>"Android/data"</i> and <i>"Android/obb"</i> on the shared storage for * privacy reasons. * Such providers should override this method. */ protected boolean shouldHide(@NonNull File file) { return (PATTERN_HIDDEN_PATH.matcher(file.getAbsolutePath()).matches()); protected boolean shouldHideDocument(@NonNull String documentId) throws FileNotFoundException { return false; } private boolean shouldShow(@NonNull File file) { return !shouldHide(file); /** * A variant of the {@link #shouldHideDocument(String)} that takes a {@link File} instead of * a {@link String} {@code documentId}. * * @see #shouldHideDocument(String) */ protected final boolean shouldHideDocument(@NonNull File document) throws FileNotFoundException { return shouldHideDocument(getDocIdForFile(document)); } protected boolean shouldBlockFromTree(@NonNull String docId) { /** * @return if the directory that should be blocked from being selected when the user launches * an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} intent. * * @see Document#FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE */ protected boolean shouldBlockDirectoryFromTree(@NonNull String documentId) throws FileNotFoundException { return false; } Loading
core/proto/android/server/activitymanagerservice.proto +1 −0 Original line number Diff line number Diff line Loading @@ -524,6 +524,7 @@ message ConnectionRecordProto { DEAD = 15; NOT_PERCEPTIBLE = 16; INCLUDE_CAPABILITIES = 17; DENY_ACTIVITY_STARTS = 18; } repeated Flag flags = 3; optional string service_name = 4; Loading
media/java/android/media/AudioDeviceAttributes.java +22 −2 Original line number Diff line number Diff line Loading @@ -64,8 +64,7 @@ public final class AudioDeviceAttributes implements Parcelable { /** * The unique address of the device. Some devices don't have addresses, only an empty string. */ private final @NonNull String mAddress; private @NonNull String mAddress; /** * Is input or output device */ Loading Loading @@ -133,6 +132,18 @@ public final class AudioDeviceAttributes implements Parcelable { mNativeType = nativeType; } /** * @hide * Copy Constructor. * @param ada the copied AudioDeviceAttributes */ public AudioDeviceAttributes(AudioDeviceAttributes ada) { mRole = ada.getRole(); mType = ada.getType(); mAddress = ada.getAddress(); mNativeType = ada.getInternalType(); } /** * @hide * Returns the role of a device Loading Loading @@ -163,6 +174,15 @@ public final class AudioDeviceAttributes implements Parcelable { return mAddress; } /** * @hide * Sets the device address. Only used by audio service. */ public void setAddress(@NonNull String address) { Objects.requireNonNull(address); mAddress = address; } /** * @hide * Returns the internal device type of a device Loading