diff options
17 files changed, 559 insertions, 441 deletions
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 4c7dd10..758b6ff 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -643,20 +643,18 @@ public abstract class Context { /** * Open a private file associated with this Context's application package - * for writing. Creates the file if it doesn't already exist. - * - * <p>No permissions are required to invoke this method, since it uses internal - * storage. + * for writing. Creates the file if it doesn't already exist. + * <p> + * No additional permissions are required for the calling app to read or + * write the returned file. * * @param name The name of the file to open; can not contain path - * separators. - * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the - * default operation, {@link #MODE_APPEND} to append to an existing file, - * {@link #MODE_WORLD_READABLE} and {@link #MODE_WORLD_WRITEABLE} to control - * permissions. - * + * separators. + * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the + * default operation, {@link #MODE_APPEND} to append to an + * existing file, {@link #MODE_WORLD_READABLE} and + * {@link #MODE_WORLD_WRITEABLE} to control permissions. * @return The resulting {@link FileOutputStream}. - * * @see #MODE_APPEND * @see #MODE_PRIVATE * @see #MODE_WORLD_READABLE @@ -689,6 +687,9 @@ public abstract class Context { /** * Returns the absolute path on the filesystem where a file created with * {@link #openFileOutput} is stored. + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. * * @param name The name of the file for which you would like to get * its path. @@ -702,14 +703,16 @@ public abstract class Context { public abstract File getFileStreamPath(String name); /** - * Returns the absolute path to the directory on the filesystem where - * files created with {@link #openFileOutput} are stored. - * - * <p>No permissions are required to read or write to the returned path, since this - * path is internal storage. + * Returns the absolute path to the directory on the filesystem where files + * created with {@link #openFileOutput} are stored. + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * <p> + * No additional permissions are required for the calling app to read or + * write files under the returned path. * * @return The path of the directory holding application files. - * * @see #openFileOutput * @see #getFileStreamPath * @see #getDir @@ -718,17 +721,19 @@ public abstract class Context { /** * Returns the absolute path to the directory on the filesystem similar to - * {@link #getFilesDir()}. The difference is that files placed under this - * directory will be excluded from automatic backup to remote storage. See + * {@link #getFilesDir()}. The difference is that files placed under this + * directory will be excluded from automatic backup to remote storage. See * {@link android.app.backup.BackupAgent BackupAgent} for a full discussion * of the automatic backup mechanism in Android. + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * <p> + * No additional permissions are required for the calling app to read or + * write files under the returned path. * - * <p>No permissions are required to read or write to the returned path, since this - * path is internal storage. - * - * @return The path of the directory holding application files that will not be - * automatically backed up to remote storage. - * + * @return The path of the directory holding application files that will not + * be automatically backed up to remote storage. * @see #openFileOutput * @see #getFileStreamPath * @see #getDir @@ -737,200 +742,256 @@ public abstract class Context { public abstract File getNoBackupFilesDir(); /** - * Returns the absolute path to the directory on the primary external filesystem - * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory() - * Environment.getExternalStorageDirectory()}) where the application can - * place persistent files it owns. These files are internal to the - * applications, and not typically visible to the user as media. - * - * <p>This is like {@link #getFilesDir()} in that these - * files will be deleted when the application is uninstalled, however there - * are some important differences: - * + * Returns the absolute path to the directory on the primary shared/external + * storage device where the application can place persistent files it owns. + * These files are internal to the applications, and not typically visible + * to the user as media. + * <p> + * This is like {@link #getFilesDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. See the - * APIs on {@link android.os.Environment} for information in the storage state. - * <li>There is no security enforced with these files. For example, any application - * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to * these files. * </ul> - * - * <p>Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions + * <p> + * If a shared storage device is emulated (as determined by + * {@link Environment#isExternalStorageEmulated(File)}), it's contents are + * backed by a private user data partition, which means there is little + * benefit to storing data here instead of the private directories returned + * by {@link #getFilesDir()}, etc. + * <p> + * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions * are required to read or write to the returned path; it's always - * accessible to the calling app. This only applies to paths generated for - * package name of the calling application. To access paths belonging - * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} - * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. - * - * <p>On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only - * have access to the external storage for the user they're running as.</p> - * - * <p>Here is an example of typical code to manipulate a file in - * an application's private storage:</p> - * + * accessible to the calling app. This only applies to paths generated for + * package name of the calling application. To access paths belonging to + * other packages, + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or + * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. + * <p> + * On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated shared storage. Applications only have + * access to the shared storage for the user they're running as. + * <p> + * The returned path may change over time if different shared storage media + * is inserted, so only relative paths should be persisted. + * <p> + * Here is an example of typical code to manipulate a file in an + * application's shared storage: + * </p> * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * private_file} - * - * <p>If you supply a non-null <var>type</var> to this function, the returned - * file will be a path to a sub-directory of the given type. Though these files - * are not automatically scanned by the media scanner, you can explicitly - * add them to the media database with - * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[], - * android.media.MediaScannerConnection.OnScanCompletedListener) - * MediaScannerConnection.scanFile}. - * Note that this is not the same as + * <p> + * If you supply a non-null <var>type</var> to this function, the returned + * file will be a path to a sub-directory of the given type. Though these + * files are not automatically scanned by the media scanner, you can + * explicitly add them to the media database with + * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[], android.media.MediaScannerConnection.OnScanCompletedListener) + * MediaScannerConnection.scanFile}. Note that this is not the same as * {@link android.os.Environment#getExternalStoragePublicDirectory * Environment.getExternalStoragePublicDirectory()}, which provides - * directories of media shared by all applications. The - * directories returned here are - * owned by the application, and their contents will be removed when the - * application is uninstalled. Unlike + * directories of media shared by all applications. The directories returned + * here are owned by the application, and their contents will be removed + * when the application is uninstalled. Unlike * {@link android.os.Environment#getExternalStoragePublicDirectory - * Environment.getExternalStoragePublicDirectory()}, the directory - * returned here will be automatically created for you. - * - * <p>Here is an example of typical code to manipulate a picture in - * an application's private storage and add it to the media database:</p> - * + * Environment.getExternalStoragePublicDirectory()}, the directory returned + * here will be automatically created for you. + * <p> + * Here is an example of typical code to manipulate a picture in an + * application's shared storage and add it to the media database: + * </p> * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * private_picture} * - * @param type The type of files directory to return. May be null for - * the root of the files directory or one of - * the following Environment constants for a subdirectory: - * {@link android.os.Environment#DIRECTORY_MUSIC}, - * {@link android.os.Environment#DIRECTORY_PODCASTS}, - * {@link android.os.Environment#DIRECTORY_RINGTONES}, - * {@link android.os.Environment#DIRECTORY_ALARMS}, - * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, - * {@link android.os.Environment#DIRECTORY_PICTURES}, or - * {@link android.os.Environment#DIRECTORY_MOVIES}. - * - * @return The path of the directory holding application files - * on external storage. Returns null if external storage is not currently - * mounted so it could not ensure the path exists; you will need to call - * this method again when it is available. - * + * @param type The type of files directory to return. May be {@code null} + * for the root of the files directory or one of the following + * constants for a subdirectory: + * {@link android.os.Environment#DIRECTORY_MUSIC}, + * {@link android.os.Environment#DIRECTORY_PODCASTS}, + * {@link android.os.Environment#DIRECTORY_RINGTONES}, + * {@link android.os.Environment#DIRECTORY_ALARMS}, + * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, + * {@link android.os.Environment#DIRECTORY_PICTURES}, or + * {@link android.os.Environment#DIRECTORY_MOVIES}. + * @return the absolute path to application-specific directory. May return + * {@code null} if shared storage is not currently available. * @see #getFilesDir - * @see android.os.Environment#getExternalStoragePublicDirectory + * @see #getExternalFilesDirs(String) + * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ @Nullable public abstract File getExternalFilesDir(@Nullable String type); /** * Returns absolute paths to application-specific directories on all - * external storage devices where the application can place persistent files - * it owns. These files are internal to the application, and not typically - * visible to the user as media. + * shared/external storage devices where the application can place + * persistent files it owns. These files are internal to the application, + * and not typically visible to the user as media. * <p> - * This is like {@link #getFilesDir()} in that these files will be deleted when - * the application is uninstalled, however there are some important differences: + * This is like {@link #getFilesDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. - * <li>There is no security enforced with these files. + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * these files. * </ul> * <p> - * External storage devices returned here are considered a permanent part of - * the device, including both emulated external storage and physical media - * slots, such as SD cards in a battery compartment. The returned paths do - * not include transient devices, such as USB flash drives. + * If a shared storage device is emulated (as determined by + * {@link Environment#isExternalStorageEmulated(File)}), it's contents are + * backed by a private user data partition, which means there is little + * benefit to storing data here instead of the private directories returned + * by {@link #getFilesDir()}, etc. + * <p> + * Shared storage devices returned here are considered a stable part of the + * device, including physical media slots under a protective cover. The + * returned paths do not include transient devices, such as USB flash drives + * connected to handheld devices. * <p> - * An application may store data on any or all of the returned devices. For + * An application may store data on any or all of the returned devices. For * example, an app may choose to store large files on the device with the * most available space, as measured by {@link StatFs}. * <p> - * No permissions are required to read or write to the returned paths; they - * are always accessible to the calling app. Write access outside of these - * paths on secondary external storage devices is not available. + * No additional permissions are required for the calling app to read or + * write files under the returned path. Write access outside of these paths + * on secondary external storage devices is not available. * <p> - * The first path returned is the same as {@link #getExternalFilesDir(String)}. - * Returned paths may be {@code null} if a storage device is unavailable. - * + * The returned path may change over time if different shared storage media + * is inserted, so only relative paths should be persisted. + * + * @param type The type of files directory to return. May be {@code null} + * for the root of the files directory or one of the following + * constants for a subdirectory: + * {@link android.os.Environment#DIRECTORY_MUSIC}, + * {@link android.os.Environment#DIRECTORY_PODCASTS}, + * {@link android.os.Environment#DIRECTORY_RINGTONES}, + * {@link android.os.Environment#DIRECTORY_ALARMS}, + * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, + * {@link android.os.Environment#DIRECTORY_PICTURES}, or + * {@link android.os.Environment#DIRECTORY_MOVIES}. + * @return the absolute paths to application-specific directories. Some + * individual paths may be {@code null} if that shared storage is + * not currently available. The first path returned is the same as + * {@link #getExternalFilesDir(String)}. * @see #getExternalFilesDir(String) * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ public abstract File[] getExternalFilesDirs(String type); /** - * Return the primary external storage directory where this application's OBB - * files (if there are any) can be found. Note if the application does not have - * any OBB files, this directory may not exist. + * Return the primary shared/external storage directory where this + * application's OBB files (if there are any) can be found. Note if the + * application does not have any OBB files, this directory may not exist. * <p> - * This is like {@link #getFilesDir()} in that these files will be deleted when - * the application is uninstalled, however there are some important differences: + * This is like {@link #getFilesDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. - * <li>There is no security enforced with these files. For example, any application - * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to * these files. * </ul> * <p> * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions * are required to read or write to the returned path; it's always - * accessible to the calling app. This only applies to paths generated for - * package name of the calling application. To access paths belonging - * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} - * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. + * accessible to the calling app. This only applies to paths generated for + * package name of the calling application. To access paths belonging to + * other packages, + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or + * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. * <p> * On devices with multiple users (as described by {@link UserManager}), * multiple users may share the same OBB storage location. Applications * should ensure that multiple instances running under different users don't * interfere with each other. + * + * @return the absolute path to application-specific directory. May return + * {@code null} if shared storage is not currently available. + * @see #getObbDirs() + * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ public abstract File getObbDir(); /** * Returns absolute paths to application-specific directories on all - * external storage devices where the application's OBB files (if there are - * any) can be found. Note if the application does not have any OBB files, - * these directories may not exist. + * shared/external storage devices where the application's OBB files (if + * there are any) can be found. Note if the application does not have any + * OBB files, these directories may not exist. * <p> - * This is like {@link #getFilesDir()} in that these files will be deleted when - * the application is uninstalled, however there are some important differences: + * This is like {@link #getFilesDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. - * <li>There is no security enforced with these files. + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * these files. * </ul> * <p> - * External storage devices returned here are considered a permanent part of - * the device, including both emulated external storage and physical media - * slots, such as SD cards in a battery compartment. The returned paths do - * not include transient devices, such as USB flash drives. + * Shared storage devices returned here are considered a stable part of the + * device, including physical media slots under a protective cover. The + * returned paths do not include transient devices, such as USB flash drives + * connected to handheld devices. * <p> - * An application may store data on any or all of the returned devices. For + * An application may store data on any or all of the returned devices. For * example, an app may choose to store large files on the device with the * most available space, as measured by {@link StatFs}. * <p> - * No permissions are required to read or write to the returned paths; they - * are always accessible to the calling app. Write access outside of these - * paths on secondary external storage devices is not available. - * <p> - * The first path returned is the same as {@link #getObbDir()}. - * Returned paths may be {@code null} if a storage device is unavailable. - * + * No additional permissions are required for the calling app to read or + * write files under the returned path. Write access outside of these paths + * on secondary external storage devices is not available. + * + * @return the absolute paths to application-specific directories. Some + * individual paths may be {@code null} if that shared storage is + * not currently available. The first path returned is the same as + * {@link #getObbDir()} * @see #getObbDir() * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ public abstract File[] getObbDirs(); /** - * Returns the absolute path to the application specific cache directory - * on the filesystem. These files will be ones that get deleted first when the - * device runs low on storage. - * There is no guarantee when these files will be deleted. - * + * Returns the absolute path to the application specific cache directory on + * the filesystem. These files will be ones that get deleted first when the + * device runs low on storage. There is no guarantee when these files will + * be deleted. + * <p> * <strong>Note: you should not <em>rely</em> on the system deleting these * files for you; you should always have a reasonable maximum, such as 1 MB, * for the amount of space you consume with cache files, and prune those * files when exceeding that space.</strong> + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * <p> + * Apps require no extra permissions to read or write to the returned path, + * since this path lives in their private storage. * * @return The path of the directory holding application cache files. - * * @see #openFileOutput * @see #getFileStreamPath * @see #getDir @@ -946,6 +1007,9 @@ public abstract class Context { * This location is optimal for storing compiled or optimized code generated * by your application at runtime. * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * <p> * Apps require no extra permissions to read or write to the returned path, * since this path lives in their private storage. * @@ -954,120 +1018,161 @@ public abstract class Context { public abstract File getCodeCacheDir(); /** - * Returns the absolute path to the directory on the primary external filesystem - * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory() - * Environment.getExternalStorageDirectory()} where the application can - * place cache files it owns. These files are internal to the application, and - * not typically visible to the user as media. - * - * <p>This is like {@link #getCacheDir()} in that these - * files will be deleted when the application is uninstalled, however there - * are some important differences: - * + * Returns absolute path to application-specific directory on the primary + * shared/external storage device where the application can place cache + * files it owns. These files are internal to the application, and not + * typically visible to the user as media. + * <p> + * This is like {@link #getCacheDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>The platform does not always monitor the space available in external - * storage, and thus may not automatically delete these files. Currently - * the only time files here will be deleted by the platform is when running - * on {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and - * {@link android.os.Environment#isExternalStorageEmulated() - * Environment.isExternalStorageEmulated()} returns true. Note that you should - * be managing the maximum space you will use for these anyway, just like - * with {@link #getCacheDir()}. - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. See the - * APIs on {@link android.os.Environment} for information in the storage state. - * <li>There is no security enforced with these files. For example, any application - * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * <li>The platform does not always monitor the space available in shared + * storage, and thus may not automatically delete these files. Apps should + * always manage the maximum space used in this location. Currently the only + * time files here will be deleted by the platform is when running on + * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and + * {@link Environment#isExternalStorageEmulated(File)} returns true. + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to * these files. * </ul> - * - * <p>Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions + * <p> + * If a shared storage device is emulated (as determined by + * {@link Environment#isExternalStorageEmulated(File)}), it's contents are + * backed by a private user data partition, which means there is little + * benefit to storing data here instead of the private directory returned by + * {@link #getCacheDir()}. + * <p> + * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions * are required to read or write to the returned path; it's always - * accessible to the calling app. This only applies to paths generated for - * package name of the calling application. To access paths belonging - * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} - * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. - * - * <p>On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only - * have access to the external storage for the user they're running as.</p> - * - * @return The path of the directory holding application cache files - * on external storage. Returns null if external storage is not currently - * mounted so it could not ensure the path exists; you will need to call - * this method again when it is available. + * accessible to the calling app. This only applies to paths generated for + * package name of the calling application. To access paths belonging to + * other packages, + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or + * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required. + * <p> + * On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated shared storage. Applications only have + * access to the shared storage for the user they're running as. + * <p> + * The returned path may change over time if different shared storage media + * is inserted, so only relative paths should be persisted. * + * @return the absolute path to application-specific directory. May return + * {@code null} if shared storage is not currently available. * @see #getCacheDir + * @see #getExternalCacheDirs() + * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ @Nullable public abstract File getExternalCacheDir(); /** * Returns absolute paths to application-specific directories on all - * external storage devices where the application can place cache files it - * owns. These files are internal to the application, and not typically - * visible to the user as media. + * shared/external storage devices where the application can place cache + * files it owns. These files are internal to the application, and not + * typically visible to the user as media. * <p> - * This is like {@link #getCacheDir()} in that these files will be deleted when - * the application is uninstalled, however there are some important differences: + * This is like {@link #getCacheDir()} in that these files will be deleted + * when the application is uninstalled, however there are some important + * differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. - * <li>There is no security enforced with these files. + * <li>The platform does not always monitor the space available in shared + * storage, and thus may not automatically delete these files. Apps should + * always manage the maximum space used in this location. Currently the only + * time files here will be deleted by the platform is when running on + * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and + * {@link Environment#isExternalStorageEmulated(File)} returns true. + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * these files. * </ul> * <p> - * External storage devices returned here are considered a permanent part of - * the device, including both emulated external storage and physical media - * slots, such as SD cards in a battery compartment. The returned paths do - * not include transient devices, such as USB flash drives. + * If a shared storage device is emulated (as determined by + * {@link Environment#isExternalStorageEmulated(File)}), it's contents are + * backed by a private user data partition, which means there is little + * benefit to storing data here instead of the private directory returned by + * {@link #getCacheDir()}. + * <p> + * Shared storage devices returned here are considered a stable part of the + * device, including physical media slots under a protective cover. The + * returned paths do not include transient devices, such as USB flash drives + * connected to handheld devices. * <p> - * An application may store data on any or all of the returned devices. For + * An application may store data on any or all of the returned devices. For * example, an app may choose to store large files on the device with the * most available space, as measured by {@link StatFs}. * <p> - * No permissions are required to read or write to the returned paths; they - * are always accessible to the calling app. Write access outside of these - * paths on secondary external storage devices is not available. + * No additional permissions are required for the calling app to read or + * write files under the returned path. Write access outside of these paths + * on secondary external storage devices is not available. * <p> - * The first path returned is the same as {@link #getExternalCacheDir()}. - * Returned paths may be {@code null} if a storage device is unavailable. + * The returned paths may change over time if different shared storage media + * is inserted, so only relative paths should be persisted. * + * @return the absolute paths to application-specific directories. Some + * individual paths may be {@code null} if that shared storage is + * not currently available. The first path returned is the same as + * {@link #getExternalCacheDir()}. * @see #getExternalCacheDir() * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ public abstract File[] getExternalCacheDirs(); /** * Returns absolute paths to application-specific directories on all - * external storage devices where the application can place media files. - * These files are scanned and made available to other apps through + * shared/external storage devices where the application can place media + * files. These files are scanned and made available to other apps through * {@link MediaStore}. * <p> * This is like {@link #getExternalFilesDirs} in that these files will be * deleted when the application is uninstalled, however there are some * important differences: * <ul> - * <li>External files are not always available: they will disappear if the - * user mounts the external storage on a computer or removes it. - * <li>There is no security enforced with these files. + * <li>Shared storage may not always be available, since removable media can + * be ejected by the user. Media state can be checked using + * {@link Environment#getExternalStorageState(File)}. + * <li>There is no security enforced with these files. For example, any + * application holding + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to + * these files. * </ul> * <p> - * External storage devices returned here are considered a permanent part of - * the device, including both emulated external storage and physical media - * slots, such as SD cards in a battery compartment. The returned paths do - * not include transient devices, such as USB flash drives. + * Shared storage devices returned here are considered a stable part of the + * device, including physical media slots under a protective cover. The + * returned paths do not include transient devices, such as USB flash drives + * connected to handheld devices. * <p> * An application may store data on any or all of the returned devices. For * example, an app may choose to store large files on the device with the * most available space, as measured by {@link StatFs}. * <p> - * No permissions are required to read or write to the returned paths; they - * are always accessible to the calling app. Write access outside of these - * paths on secondary external storage devices is not available. + * No additional permissions are required for the calling app to read or + * write files under the returned path. Write access outside of these paths + * on secondary external storage devices is not available. * <p> - * Returned paths may be {@code null} if a storage device is unavailable. + * The returned paths may change over time if different shared storage media + * is inserted, so only relative paths should be persisted. * + * @return the absolute paths to application-specific directories. Some + * individual paths may be {@code null} if that shared storage is + * not currently available. * @see Environment#getExternalStorageState(File) + * @see Environment#isExternalStorageEmulated(File) + * @see Environment#isExternalStorageRemovable(File) */ public abstract File[] getExternalMediaDirs(); @@ -1090,6 +1195,12 @@ public abstract class Context { * created through a File object will only be accessible by your own * application; you can only set the mode of the entire directory, not * of individual files. + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * <p> + * Apps require no extra permissions to read or write to the returned path, + * since this path lives in their private storage. * * @param name Name of the directory to retrieve. This is a directory * that is created as part of your application data. @@ -1173,6 +1284,9 @@ public abstract class Context { /** * Returns the absolute path on the filesystem where a database created with * {@link #openOrCreateDatabase} is stored. + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. * * @param name The name of the database for which you would like to get * its path. diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 64d6da5..f346fe7 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -276,8 +276,8 @@ public class Environment { } /** - * Return the primary external storage directory. This directory may not - * currently be accessible if it has been mounted by the user on their + * Return the primary shared/external storage directory. This directory may + * not currently be accessible if it has been mounted by the user on their * computer, has been removed from the device, or some other problem has * happened. You can determine its current state with * {@link #getExternalStorageState()}. @@ -291,12 +291,15 @@ public class Environment { * filesystem on a computer.</em> * <p> * On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only have - * access to the external storage for the user they're running as. + * each user has their own isolated shared storage. Applications only have + * access to the shared storage for the user they're running as. * <p> - * In devices with multiple "external" storage directories, this directory - * represents the "primary" external storage that the user will interact + * In devices with multiple shared/external storage directories, this + * directory represents the primary storage that the user will interact * with. Access to secondary storage is available through + * {@link Context#getExternalFilesDirs(String)}, + * {@link Context#getExternalCacheDirs()}, and + * {@link Context#getExternalMediaDirs()}. * <p> * Applications should not directly use this top-level directory, in order * to avoid polluting the user's root namespace. Any files that are private @@ -315,8 +318,9 @@ public class Environment { * <p> * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your * application only needs to store internal data, consider using - * {@link Context#getExternalFilesDir(String)} or - * {@link Context#getExternalCacheDir()}, which require no permissions to + * {@link Context#getExternalFilesDir(String)}, + * {@link Context#getExternalCacheDir()}, or + * {@link Context#getExternalMediaDirs()}, which require no permissions to * read or write. * <p> * This path may change between platform versions, so applications should @@ -325,8 +329,7 @@ public class Environment { * Here is an example of typical code to monitor the state of external * storage: * <p> - * {@sample - * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java + * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * monitor_storage} * * @see #getExternalStorageState() @@ -446,32 +449,32 @@ public class Environment { public static String DIRECTORY_DOCUMENTS = "Documents"; /** - * Get a top-level public external storage directory for placing files of - * a particular type. This is where the user will typically place and - * manage their own files, so you should be careful about what you put here - * to ensure you don't erase their files or get in the way of their own + * Get a top-level shared/external storage directory for placing files of a + * particular type. This is where the user will typically place and manage + * their own files, so you should be careful about what you put here to + * ensure you don't erase their files or get in the way of their own * organization. - * - * <p>On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only - * have access to the external storage for the user they're running as.</p> - * - * <p>Here is an example of typical code to manipulate a picture on - * the public external storage:</p> - * + * <p> + * On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated shared storage. Applications only have + * access to the shared storage for the user they're running as. + * </p> + * <p> + * Here is an example of typical code to manipulate a picture on the public + * shared storage: + * </p> * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * public_picture} * - * @param type The type of storage directory to return. Should be one of - * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, - * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, - * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, - * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or - * {@link #DIRECTORY_DCIM}. May not be null. - * - * @return Returns the File path for the directory. Note that this - * directory may not yet exist, so you must make sure it exists before - * using it such as with {@link File#mkdirs File.mkdirs()}. + * @param type The type of storage directory to return. Should be one of + * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, + * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, + * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, + * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or + * {@link #DIRECTORY_DCIM}. May not be null. + * @return Returns the File path for the directory. Note that this directory + * may not yet exist, so you must make sure it exists before using + * it such as with {@link File#mkdirs File.mkdirs()}. */ public static File getExternalStoragePublicDirectory(String type) { throwIfUserRequired(); @@ -623,7 +626,7 @@ public class Environment { public static final String MEDIA_EJECTING = "ejecting"; /** - * Returns the current state of the primary "external" storage device. + * Returns the current state of the primary shared/external storage media. * * @see #getExternalStorageDirectory() * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, @@ -646,8 +649,8 @@ public class Environment { } /** - * Returns the current state of the storage device that provides the given - * path. + * Returns the current state of the shared/external storage media at the + * given path. * * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, @@ -665,7 +668,8 @@ public class Environment { } /** - * Returns whether the primary "external" storage device is removable. + * Returns whether the primary shared/external storage media is physically + * removable. * * @return true if the storage device can be removed (such as an SD card), * or false if the storage device is built in and cannot be @@ -678,8 +682,8 @@ public class Environment { } /** - * Returns whether the storage device that provides the given path is - * removable. + * Returns whether the shared/external storage media at the given path is + * physically removable. * * @return true if the storage device can be removed (such as an SD card), * or false if the storage device is built in and cannot be @@ -697,9 +701,15 @@ public class Environment { } /** - * Returns whether the primary "external" storage device is emulated. If - * true, data stored on this device will be stored on a portion of the - * internal storage system. + * Returns whether the primary shared/external storage media is emulated. + * <p> + * The contents of emulated storage devices are backed by a private user + * data partition, which means there is little benefit to apps storing data + * here instead of the private directories returned by + * {@link Context#getFilesDir()}, etc. + * <p> + * This returns true when emulated storage is backed by either internal + * storage or an adopted storage device. * * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName, * boolean) @@ -711,9 +721,16 @@ public class Environment { } /** - * Returns whether the storage device that provides the given path is - * emulated. If true, data stored on this device will be stored on a portion - * of the internal storage system. + * Returns whether the shared/external storage media at the given path is + * emulated. + * <p> + * The contents of emulated storage devices are backed by a private user + * data partition, which means there is little benefit to apps storing data + * here instead of the private directories returned by + * {@link Context#getFilesDir()}, etc. + * <p> + * This returns true when emulated storage is backed by either internal + * storage or an adopted storage device. * * @throws IllegalArgumentException if the path is not a valid storage * device. diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index db19f7a..8763496 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -41,6 +41,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.Locale; import java.util.Objects; import java.util.UUID; @@ -68,6 +69,7 @@ public class ZenModeConfig implements Parcelable { public static final int[] MINUTE_BUCKETS = generateMinuteBuckets(); private static final int SECONDS_MS = 1000; private static final int MINUTES_MS = 60 * SECONDS_MS; + private static final int DAY_MINUTES = 24 * 60; private static final int ZERO_VALUE_MS = 10 * SECONDS_MS; private static final boolean DEFAULT_ALLOW_CALLS = true; @@ -652,40 +654,68 @@ public class ZenModeConfig implements Parcelable { boolean shortVersion) { final long now = System.currentTimeMillis(); final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS; - return toTimeCondition(context, now + millis, minutesFromNow, now, userHandle, - shortVersion); + return toTimeCondition(context, now + millis, minutesFromNow, userHandle, shortVersion); } - public static Condition toTimeCondition(Context context, long time, int minutes, long now, + public static Condition toTimeCondition(Context context, long time, int minutes, int userHandle, boolean shortVersion) { - final int num, summaryResId, line1ResId; + final int num; + String summary, line1, line2; + final CharSequence formattedTime = getFormattedTime(context, time, userHandle); + final Resources res = context.getResources(); if (minutes < 60) { // display as minutes num = minutes; - summaryResId = shortVersion ? R.plurals.zen_mode_duration_minutes_summary_short + int summaryResId = shortVersion ? R.plurals.zen_mode_duration_minutes_summary_short : R.plurals.zen_mode_duration_minutes_summary; - line1ResId = shortVersion ? R.plurals.zen_mode_duration_minutes_short + summary = res.getQuantityString(summaryResId, num, num, formattedTime); + int line1ResId = shortVersion ? R.plurals.zen_mode_duration_minutes_short : R.plurals.zen_mode_duration_minutes; - } else { + line1 = res.getQuantityString(line1ResId, num, num, formattedTime); + line2 = res.getString(R.string.zen_mode_until, formattedTime); + } else if (minutes < DAY_MINUTES) { // display as hours num = Math.round(minutes / 60f); - summaryResId = shortVersion ? R.plurals.zen_mode_duration_hours_summary_short + int summaryResId = shortVersion ? R.plurals.zen_mode_duration_hours_summary_short : R.plurals.zen_mode_duration_hours_summary; - line1ResId = shortVersion ? R.plurals.zen_mode_duration_hours_short + summary = res.getQuantityString(summaryResId, num, num, formattedTime); + int line1ResId = shortVersion ? R.plurals.zen_mode_duration_hours_short : R.plurals.zen_mode_duration_hours; + line1 = res.getQuantityString(line1ResId, num, num, formattedTime); + line2 = res.getString(R.string.zen_mode_until, formattedTime); + } else { + // display as day/time + summary = line1 = line2 = res.getString(R.string.zen_mode_until, formattedTime); } - final String skeleton = DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma"; - final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); - final CharSequence formattedTime = DateFormat.format(pattern, time); - final Resources res = context.getResources(); - final String summary = res.getQuantityString(summaryResId, num, num, formattedTime); - final String line1 = res.getQuantityString(line1ResId, num, num, formattedTime); - final String line2 = res.getString(R.string.zen_mode_until, formattedTime); final Uri id = toCountdownConditionId(time); return new Condition(id, summary, line1, line2, 0, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_NOW); } + public static Condition toNextAlarmCondition(Context context, long now, long alarm, + int userHandle) { + final CharSequence formattedTime = getFormattedTime(context, alarm, userHandle); + final Resources res = context.getResources(); + final String line1 = res.getString(R.string.zen_mode_alarm, formattedTime); + final Uri id = toCountdownConditionId(alarm); + return new Condition(id, "", line1, "", 0, Condition.STATE_TRUE, + Condition.FLAG_RELEVANT_NOW); + } + + private static CharSequence getFormattedTime(Context context, long time, int userHandle) { + String skeleton = "EEE " + (DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma"); + GregorianCalendar now = new GregorianCalendar(); + GregorianCalendar endTime = new GregorianCalendar(); + endTime.setTimeInMillis(time); + if (now.get(Calendar.YEAR) == endTime.get(Calendar.YEAR) + && now.get(Calendar.MONTH) == endTime.get(Calendar.MONTH) + && now.get(Calendar.DATE) == endTime.get(Calendar.DATE)) { + skeleton = DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma"; + } + final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); + return DateFormat.format(pattern, time); + } + // ==== Built-in system conditions ==== public static final String SYSTEM_AUTHORITY = "android"; @@ -883,11 +913,6 @@ public class ZenModeConfig implements Parcelable { return UUID.randomUUID().toString().replace("-", ""); } - public static String getConditionLine1(Context context, ZenModeConfig config, - int userHandle, boolean shortVersion) { - return getConditionLine(context, config, userHandle, true /*useLine1*/, shortVersion); - } - public static String getConditionSummary(Context context, ZenModeConfig config, int userHandle, boolean shortVersion) { return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion); @@ -906,8 +931,8 @@ public class ZenModeConfig implements Parcelable { if (time > 0) { final long now = System.currentTimeMillis(); final long span = time - now; - c = toTimeCondition(context, - time, Math.round(span / (float) MINUTES_MS), now, userHandle, shortVersion); + c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS), + userHandle, shortVersion); } final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary; return TextUtils.isEmpty(rt) ? "" : rt; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 07984e9..c222a82 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -578,7 +578,7 @@ public abstract class Window { void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) { CharSequence curTitle = wp.getTitle(); if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && - wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { if (wp.token == null) { View decor = peekDecorView(); if (decor != null) { @@ -588,25 +588,38 @@ public abstract class Window { if (curTitle == null || curTitle.length() == 0) { String title; if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) { - title="Media"; + title = "Media"; } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) { - title="MediaOvr"; + title = "MediaOvr"; } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - title="Panel"; + title = "Panel"; } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) { - title="SubPanel"; + title = "SubPanel"; } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL) { - title="AboveSubPanel"; + title = "AboveSubPanel"; } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) { - title="AtchDlg"; + title = "AtchDlg"; } else { - title=Integer.toString(wp.type); + title = Integer.toString(wp.type); } if (mAppName != null) { title += ":" + mAppName; } wp.setTitle(title); } + } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW && + wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { + // We don't set the app token to this system window because the life cycles should be + // independent. If an app creates a system window and then the app goes to the stopped + // state, the system window should not be affected (can still show and receive input + // events). + if (curTitle == null || curTitle.length() == 0) { + String title = "Sys" + Integer.toString(wp.type); + if (mAppName != null) { + title += ":" + mAppName; + } + wp.setTitle(title); + } } else { if (wp.token == null) { wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 9708cce..c6b340b 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -920,7 +920,7 @@ public class ChooserActivity extends ResolverActivity { @Override public int compare(ChooserTarget lhs, ChooserTarget rhs) { // Descending order - return (int) Math.signum(lhs.getScore() - rhs.getScore()); + return (int) Math.signum(rhs.getScore() - lhs.getScore()); } } diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 44df0ce..b44baa2 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -35,7 +35,7 @@ import java.util.Arrays; public class FloatingActionMode extends ActionMode { private static final int MAX_HIDE_DURATION = 3000; - private static final int MOVING_HIDE_DELAY = 300; + private static final int MOVING_HIDE_DELAY = 50; private final Context mContext; private final ActionMode.Callback2 mCallback; @@ -181,7 +181,6 @@ public class FloatingActionMode extends ActionMode { // Content rect is moving. mOriginatingView.removeCallbacks(mMovingOff); mFloatingToolbarVisibilityHelper.setMoving(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); mFloatingToolbar.setContentRect(mContentRectOnScreen); @@ -189,9 +188,9 @@ public class FloatingActionMode extends ActionMode { } } else { mFloatingToolbarVisibilityHelper.setOutOfBounds(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mContentRectOnScreen.setEmpty(); } + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mPreviousContentRectOnScreen.set(mContentRectOnScreen); } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index ca6fe61..2a25db6 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -1488,10 +1488,9 @@ public final class FloatingToolbar { private static AnimatorSet createEnterAnimation(View view) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200), + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150), // Make sure that view.x is always fixed throughout the duration of this animation. ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); - animation.setStartDelay(50); return animation; } @@ -1506,7 +1505,7 @@ public final class FloatingToolbar { View view, int startDelay, Animator.AnimatorListener listener) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200)); + ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); animation.setStartDelay(startDelay); animation.addListener(listener); return animation; diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml index d37f5b7..c2a2a26 100644 --- a/core/res/res/drawable/spinner_background_material.xml +++ b/core/res/res/drawable/spinner_background_material.xml @@ -17,18 +17,18 @@ <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:paddingMode="stack" android:paddingStart="0dp" - android:paddingEnd="24dp" + android:paddingEnd="48dp" android:paddingLeft="0dp" android:paddingRight="0dp"> <item - android:gravity="end|center_vertical" - android:width="24dp" - android:height="24dp" + android:gravity="end|fill_vertical" + android:width="48dp" android:drawable="@drawable/control_background_40dp_material" /> <item android:drawable="@drawable/ic_spinner_caret" android:gravity="end|center_vertical" android:width="24dp" - android:height="24dp" /> + android:height="24dp" + android:end="12dp" /> </layer-list> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d9fa287..8a9b9cf 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4036,6 +4036,9 @@ <!-- Zen mode condition - line two: ending time. [CHAR LIMIT=NONE] --> <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string> + <!-- Zen mode condition - line one: Until next alarm. [CHAR LIMIT=NONE] --> + <string name="zen_mode_alarm">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g> (next alarm)</string> + <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] --> <string name="zen_mode_forever">Until you turn this off</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 95cd143..52892ba 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2083,6 +2083,7 @@ <java-symbol type="string" name="zen_mode_default_events_name" /> <java-symbol type="array" name="config_system_condition_providers" /> <java-symbol type="string" name="muted_by" /> + <java-symbol type="string" name="zen_mode_alarm" /> <java-symbol type="string" name="select_day" /> <java-symbol type="string" name="select_year" /> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index b2df40a..0e91b0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -27,7 +27,6 @@ public interface ZenModeController { void removeCallback(Callback callback); void setZen(int zen, Uri conditionId, String reason); int getZen(); - void requestConditions(boolean request); ZenRule getManualRule(); ZenModeConfig getConfig(); long getNextAlarm(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index c07f1a8..96efea1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -121,15 +121,6 @@ public class ZenModeControllerImpl implements ZenModeController { } @Override - public void requestConditions(boolean request) { - mRequesting = request; - mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0); - if (!mRequesting) { - mConditions.clear(); - } - } - - @Override public ZenRule getManualRule() { return mConfig == null ? null : mConfig.manualRule; } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 3c9a7fc..3337714 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -58,6 +58,8 @@ import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.Locale; import java.util.Objects; @@ -76,6 +78,8 @@ public class ZenModePanel extends LinearLayout { private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60); private static final int FOREVER_CONDITION_INDEX = 0; private static final int COUNTDOWN_CONDITION_INDEX = 1; + private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2; + private static final int COUNTDOWN_CONDITION_COUNT = 2; public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); @@ -86,7 +90,6 @@ public class ZenModePanel extends LinearLayout { private final LayoutInflater mInflater; private final H mHandler = new H(); private final ZenPrefs mPrefs; - private final IconPulser mIconPulser; private final TransitionHelper mTransitionHelper = new TransitionHelper(); private final Uri mForeverId; private final SpTexts mSpTexts; @@ -104,9 +107,6 @@ public class ZenModePanel extends LinearLayout { private Callback mCallback; private ZenModeController mController; private boolean mCountdownConditionSupported; - private int mMaxConditions; - private int mMaxOptionalConditions; - private int mFirstConditionIndex; private boolean mRequestingConditions; private Condition mExitCondition; private int mBucketIndex = -1; @@ -125,7 +125,6 @@ public class ZenModePanel extends LinearLayout { mContext = context; mPrefs = new ZenPrefs(); mInflater = LayoutInflater.from(mContext.getApplicationContext()); - mIconPulser = new IconPulser(mContext); mForeverId = Condition.newId(mContext).appendPath("forever").build(); mSpTexts = new SpTexts(mContext); mVoiceCapable = Util.isVoiceCapable(mContext); @@ -135,7 +134,6 @@ public class ZenModePanel extends LinearLayout { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("ZenModePanel state:"); pw.print(" mCountdownConditionSupported="); pw.println(mCountdownConditionSupported); - pw.print(" mMaxConditions="); pw.println(mMaxConditions); pw.print(" mRequestingConditions="); pw.println(mRequestingConditions); pw.print(" mAttached="); pw.println(mAttached); pw.print(" mHidden="); pw.println(mHidden); @@ -286,14 +284,6 @@ public class ZenModePanel extends LinearLayout { if (mRequestingConditions == requesting) return; if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting); mRequestingConditions = requesting; - if (mController != null) { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - mController.requestConditions(requesting); - } - }); - } if (mRequestingConditions) { mTimeCondition = parseExistingTimeCondition(mContext, mExitCondition); if (mTimeCondition != null) { @@ -304,6 +294,7 @@ public class ZenModePanel extends LinearLayout { MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser()); } if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); + mConditions = null; // reset conditions handleUpdateConditions(); } else { @@ -314,13 +305,9 @@ public class ZenModePanel extends LinearLayout { public void init(ZenModeController controller) { mController = controller; mCountdownConditionSupported = mController.isCountdownConditionSupported(); - final int countdownDelta = mCountdownConditionSupported ? 1 : 0; - mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta; + final int countdownDelta = mCountdownConditionSupported ? COUNTDOWN_CONDITION_COUNT : 0; final int minConditions = 1 /*forever*/ + countdownDelta; - mMaxConditions = MathUtils.constrain(mContext.getResources() - .getInteger(R.integer.zen_mode_max_conditions), minConditions, 100); - mMaxOptionalConditions = mMaxConditions - minConditions; - for (int i = 0; i < mMaxConditions; i++) { + for (int i = 0; i < minConditions; i++) { mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false)); } mSessionZen = getSelectedZen(-1); @@ -357,28 +344,10 @@ public class ZenModePanel extends LinearLayout { return condition == null ? null : condition.copy(); } - public static String getExitConditionText(Context context, Condition exitCondition) { - if (exitCondition == null) { - return foreverSummary(context); - } else if (isCountdown(exitCondition)) { - final Condition condition = parseExistingTimeCondition(context, exitCondition); - return condition != null ? condition.summary : foreverSummary(context); - } else { - return exitCondition.summary; - } - } - public void setCallback(Callback callback) { mCallback = callback; } - public void showSilentHint() { - if (DEBUG) Log.d(mTag, "showSilentHint"); - if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; - final View noneButton = mZenButtons.getChildAt(0); - mIconPulser.start(noneButton); - } - private void handleUpdateManualRule(ZenRule rule) { final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF; handleUpdateZen(zen); @@ -410,7 +379,7 @@ public class ZenModePanel extends LinearLayout { final ConditionTag tag = getConditionTagAt(i); if (tag != null) { if (sameConditionId(tag.condition, mExitCondition)) { - bind(exitCondition, mZenConditions.getChildAt(i)); + bind(exitCondition, mZenConditions.getChildAt(i), i); } } } @@ -495,64 +464,32 @@ public class ZenModePanel extends LinearLayout { final long span = time - now; if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null; return ZenModeConfig.toTimeCondition(context, - time, Math.round(span / (float) MINUTES_MS), now, ActivityManager.getCurrentUser(), + time, Math.round(span / (float) MINUTES_MS), ActivityManager.getCurrentUser(), false /*shortVersion*/); } - private void handleUpdateConditions(Condition[] conditions) { - conditions = trimConditions(conditions); - if (Arrays.equals(conditions, mConditions)) { - final int count = mConditions == null ? 0 : mConditions.length; - if (DEBUG) Log.d(mTag, "handleUpdateConditions unchanged conditionCount=" + count); - return; - } - mConditions = conditions; - handleUpdateConditions(); - } - - private Condition[] trimConditions(Condition[] conditions) { - if (conditions == null || conditions.length <= mMaxOptionalConditions) { - // no need to trim - return conditions; - } - // look for current exit condition, ensure it is included if found - int found = -1; - for (int i = 0; i < conditions.length; i++) { - final Condition c = conditions[i]; - if (mSessionExitCondition != null && sameConditionId(mSessionExitCondition, c)) { - found = i; - break; - } - } - final Condition[] rt = Arrays.copyOf(conditions, mMaxOptionalConditions); - if (found >= mMaxOptionalConditions) { - // found after the first N, promote to the end of the first N - rt[mMaxOptionalConditions - 1] = conditions[found]; - } - return rt; - } - private void handleUpdateConditions() { if (mTransitionHelper.isTransitioning()) { - mTransitionHelper.pendingUpdateConditions(); return; } final int conditionCount = mConditions == null ? 0 : mConditions.length; if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount); // forever - bind(forever(), mZenConditions.getChildAt(FOREVER_CONDITION_INDEX)); + bind(forever(), mZenConditions.getChildAt(FOREVER_CONDITION_INDEX), + FOREVER_CONDITION_INDEX); // countdown if (mCountdownConditionSupported && mTimeCondition != null) { - bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX)); - } - // provider conditions - for (int i = 0; i < conditionCount; i++) { - bind(mConditions[i], mZenConditions.getChildAt(mFirstConditionIndex + i)); - } - // hide the rest - for (int i = mZenConditions.getChildCount() - 1; i > mFirstConditionIndex + conditionCount; - i--) { - mZenConditions.getChildAt(i).setVisibility(GONE); + bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX), + COUNTDOWN_CONDITION_INDEX); + } + // countdown until alarm + if (mCountdownConditionSupported) { + Condition nextAlarmCondition = getTimeUntilNextAlarmCondition(); + if (nextAlarmCondition != null) { + bind(nextAlarmCondition, + mZenConditions.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX), + COUNTDOWN_ALARM_CONDITION_INDEX); + } } // ensure something is selected if (mExpanded && isShown()) { @@ -569,6 +506,33 @@ public class ZenModePanel extends LinearLayout { return context.getString(com.android.internal.R.string.zen_mode_forever); } + // Returns a time condition if the next alarm is within the next week. + private Condition getTimeUntilNextAlarmCondition() { + GregorianCalendar weekRange = new GregorianCalendar(); + final long now = weekRange.getTimeInMillis(); + setToMidnight(weekRange); + weekRange.roll(Calendar.DATE, 6); + final long nextAlarmMs = mController.getNextAlarm(); + if (nextAlarmMs > 0) { + GregorianCalendar nextAlarm = new GregorianCalendar(); + nextAlarm.setTimeInMillis(nextAlarmMs); + setToMidnight(nextAlarm); + + if (weekRange.compareTo(nextAlarm) >= 0) { + return ZenModeConfig.toNextAlarmCondition(mContext, now, nextAlarmMs, + ActivityManager.getCurrentUser()); + } + } + return null; + } + + private void setToMidnight(Calendar calendar) { + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + } + private ConditionTag getConditionTagAt(int index) { return (ConditionTag) mZenConditions.getChildAt(index).getTag(); } @@ -610,7 +574,8 @@ public class ZenModePanel extends LinearLayout { mTimeCondition = ZenModeConfig.toTimeCondition(mContext, MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser()); mBucketIndex = favoriteIndex; - bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX)); + bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX), + COUNTDOWN_CONDITION_INDEX); getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true); } } @@ -623,7 +588,7 @@ public class ZenModePanel extends LinearLayout { return c != null && mForeverId.equals(c.id); } - private void bind(final Condition condition, final View row) { + private void bind(final Condition condition, final View row, final int rowId) { if (condition == null) throw new IllegalArgumentException("condition must not be null"); final boolean enabled = condition.state == Condition.STATE_TRUE; final ConditionTag tag = @@ -640,8 +605,7 @@ public class ZenModePanel extends LinearLayout { tag.rb.setEnabled(enabled); final boolean checked = (mSessionExitCondition != null || mAttachedZen != Global.ZEN_MODE_OFF) - && (sameConditionId(mSessionExitCondition, tag.condition) - || isCountdown(mSessionExitCondition) && isCountdown(tag.condition)); + && (sameConditionId(mSessionExitCondition, tag.condition)); if (checked != tag.rb.isChecked()) { if (DEBUG) Log.d(mTag, "bind checked=" + checked + " condition=" + conditionId); tag.rb.setChecked(checked); @@ -692,7 +656,7 @@ public class ZenModePanel extends LinearLayout { button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - onClickTimeButton(row, tag, false /*down*/); + onClickTimeButton(row, tag, false /*down*/, rowId); } }); @@ -700,7 +664,7 @@ public class ZenModePanel extends LinearLayout { button2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - onClickTimeButton(row, tag, true /*up*/); + onClickTimeButton(row, tag, true /*up*/, rowId); } }); tag.lines.setOnClickListener(new OnClickListener() { @@ -711,7 +675,7 @@ public class ZenModePanel extends LinearLayout { }); final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); - if (time > 0) { + if (rowId != COUNTDOWN_ALARM_CONDITION_INDEX && time > 0) { button1.setVisibility(VISIBLE); button2.setVisibility(VISIBLE); if (mBucketIndex > -1) { @@ -761,7 +725,7 @@ public class ZenModePanel extends LinearLayout { tag.line1.getText())); } - private void onClickTimeButton(View row, ConditionTag tag, boolean up) { + private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) { MetricsLogger.action(mContext, MetricsLogger.QS_DND_TIME, up); Condition newCondition = null; final int N = MINUTE_BUCKETS.length; @@ -777,7 +741,7 @@ public class ZenModePanel extends LinearLayout { if (up && bucketTime > time || !up && bucketTime < time) { mBucketIndex = j; newCondition = ZenModeConfig.toTimeCondition(mContext, - bucketTime, bucketMinutes, now, ActivityManager.getCurrentUser(), + bucketTime, bucketMinutes, ActivityManager.getCurrentUser(), false /*shortVersion*/); break; } @@ -794,7 +758,7 @@ public class ZenModePanel extends LinearLayout { MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser()); } mTimeCondition = newCondition; - bind(mTimeCondition, row); + bind(mTimeCondition, row, rowId); tag.rb.setChecked(true); select(mTimeCondition); announceConditionSelection(tag); @@ -838,18 +802,12 @@ public class ZenModePanel extends LinearLayout { private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() { @Override - public void onConditionsChanged(Condition[] conditions) { - mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget(); - } - - @Override public void onManualRuleChanged(ZenRule rule) { mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget(); } }; private final class H extends Handler { - private static final int UPDATE_CONDITIONS = 1; private static final int MANUAL_RULE_CHANGED = 2; private static final int UPDATE_WIDGETS = 3; @@ -860,7 +818,6 @@ public class ZenModePanel extends LinearLayout { @Override public void handleMessage(Message msg) { switch (msg.what) { - case UPDATE_CONDITIONS: handleUpdateConditions((Condition[]) msg.obj); break; case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break; case UPDATE_WIDGETS: updateWidgets(); break; } @@ -1005,26 +962,20 @@ public class ZenModePanel extends LinearLayout { private final ArraySet<View> mTransitioningViews = new ArraySet<View>(); private boolean mTransitioning; - private boolean mPendingUpdateConditions; private boolean mPendingUpdateWidgets; public void clear() { mTransitioningViews.clear(); - mPendingUpdateConditions = mPendingUpdateWidgets = false; + mPendingUpdateWidgets = false; } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(" TransitionHelper state:"); - pw.print(" mPendingUpdateConditions="); pw.println(mPendingUpdateConditions); pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets); pw.print(" mTransitioning="); pw.println(mTransitioning); pw.print(" mTransitioningViews="); pw.println(mTransitioningViews); } - public void pendingUpdateConditions() { - mPendingUpdateConditions = true; - } - public void pendingUpdateWidgets() { mPendingUpdateWidgets = true; } @@ -1050,15 +1001,11 @@ public class ZenModePanel extends LinearLayout { @Override public void run() { if (DEBUG) Log.d(mTag, "TransitionHelper run" - + " mPendingUpdateWidgets=" + mPendingUpdateWidgets - + " mPendingUpdateConditions=" + mPendingUpdateConditions); + + " mPendingUpdateWidgets=" + mPendingUpdateWidgets); if (mPendingUpdateWidgets) { updateWidgets(); } - if (mPendingUpdateConditions) { - handleUpdateConditions(); - } - mPendingUpdateWidgets = mPendingUpdateConditions = false; + mPendingUpdateWidgets = false; } private void updateTransitioning() { @@ -1067,10 +1014,10 @@ public class ZenModePanel extends LinearLayout { mTransitioning = transitioning; if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning); if (!mTransitioning) { - if (mPendingUpdateConditions || mPendingUpdateWidgets) { + if (mPendingUpdateWidgets) { mHandler.post(this); } else { - mPendingUpdateConditions = mPendingUpdateWidgets = false; + mPendingUpdateWidgets = false; } } } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index e3d5d38..a2929bd 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -971,8 +971,8 @@ class AlarmManagerService extends SystemService { // This is a special alarm that will put the system into idle until it goes off. // The caller has given the time they want this to happen at, however we need // to pull that earlier if there are existing alarms that have requested to - // bring us out of idle. - if (mNextWakeFromIdle != null) { + // bring us out of idle at an earlier time. + if (mNextWakeFromIdle != null && a.whenElapsed > mNextWakeFromIdle.whenElapsed) { a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed; } // Add fuzz to make the alarm go off some time before the actual desired time. @@ -1256,7 +1256,7 @@ class AlarmManagerService extends SystemService { pw.print(" Idling until: "); if (mPendingIdleUntil != null) { pw.println(mPendingIdleUntil); - mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf); + mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf); } else { pw.println("null"); } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 06bd583..3c50102 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -73,7 +73,7 @@ import com.android.server.job.controllers.TimeController; */ public class JobSchedulerService extends com.android.server.SystemService implements StateChangedListener, JobCompletedListener { - static final boolean DEBUG = false; + public static final boolean DEBUG = false; /** The number of concurrent jobs we run at one time. */ private static final int MAX_JOB_CONTEXTS_COUNT = ActivityManager.isLowRamDeviceStatic() ? 1 : 3; @@ -99,7 +99,7 @@ public class JobSchedulerService extends com.android.server.SystemService * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule * things early. */ - static final int MIN_CONNECTIVITY_COUNT = 2; + static final int MIN_CONNECTIVITY_COUNT = 1; // Run connectivity jobs as soon as ready. /** * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running * some work early. diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 744028a..cc9003f 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -380,9 +380,9 @@ public class CarrierConfigManager { "ci_action_on_sys_update_extra_val_string"; /** - * Specifies the amount of gap to be added in millis between DTMF tones. When a non-zero value - * is specified, the UE shall wait for the specified amount of time before it sends out - * successive DTMF tones on the network. + * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a + * non-zero value is specified, the UE shall wait for the specified amount of time before it + * sends out successive DTMF tones on the network. * @hide */ public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; @@ -421,6 +421,14 @@ public class CarrierConfigManager { public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool"; /** + * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a + * non-zero value is specified, the UE shall wait for the specified amount of time before it + * sends out successive DTMF tones on the network. + * @hide + */ + public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; + + /** * If this is true, the SIM card (through Customer Service Profile EF file) will be able to * prevent manual operator selection. If false, this SIM setting will be ignored and manual * operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more @@ -544,6 +552,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true); sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false); sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false); + sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100); // MMS defaults sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false); diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 37ffa06..e11c8d3 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -334,7 +334,8 @@ public class SubscriptionInfo implements Parcelable { @Override public String toString() { - return "{id=" + mId + ", iccId=" + mIccId + " simSlotIndex=" + mSimSlotIndex + String iccIdToPrint = mIccId != null ? mIccId.substring(0, 9) + "XXXXXXXXXXX" : null; + return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex + " displayName=" + mDisplayName + " carrierName=" + mCarrierName + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc |
