diff options
Diffstat (limited to 'core/java')
66 files changed, 1205 insertions, 968 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 31e129b..993b53d 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -51,10 +51,7 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static android.Manifest.permission.AUTHENTICATE_ACCOUNTS; import static android.Manifest.permission.GET_ACCOUNTS; -import static android.Manifest.permission.MANAGE_ACCOUNTS; -import static android.Manifest.permission.USE_CREDENTIALS; /** * This class provides access to a centralized registry of the user's @@ -319,14 +316,12 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that owns the specified account. * - * @param account The account to query for a password + * @param account The account to query for a password. Must not be {@code null}. * @return The account's password, null if none or if the account doesn't exist */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String getPassword(final Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -345,14 +340,12 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that owns the specified account. * * @param account The account to query for user data * @return The user data, null if the account or key doesn't exist */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String getUserData(final Account account, final String key) { if (account == null) throw new IllegalArgumentException("account is null"); if (key == null) throw new IllegalArgumentException("key is null"); @@ -662,10 +655,8 @@ public class AccountManager { * wizards associated with authenticators, not directly by applications. * * <p>It is safe to call this method from the main thread. - * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the added account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that owns the specified account. * * @param account The {@link Account} to add * @param password The password to associate with the account, null for none @@ -673,7 +664,6 @@ public class AccountManager { * @return True if the account was successfully added, false if the account * already exists, the account is null, or another error occurs. */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -692,14 +682,13 @@ public class AccountManager { * <p> * It is not safe to call this method from the main thread. As such, call it * from another thread. - * <p> - * This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be - * called from the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that owns the specified account. * * @param account The {@link Account} to be updated. + * @return boolean {@code true} if the authentication of the account has been successfully + * acknowledged. Otherwise {@code false}. */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean notifyAccountAuthenticated(Account account) { if (account == null) throw new IllegalArgumentException("account is null"); @@ -717,9 +706,8 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * * @param account The {@link Account} to rename * @param newName String name to be associated with the account. @@ -731,7 +719,6 @@ public class AccountManager { * after the name change. If successful the account's name will be the * specified new name. */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public AccountManagerFuture<Account> renameAccount( final Account account, @Size(min = 1) final String newName, @@ -783,11 +770,8 @@ public class AccountManager { * The authenticator may have its own policies preventing account * deletion, in which case the account will not be deleted. * - * <p>This method may be called from any thread, but the returned - * {@link AccountManagerFuture} must not be used on the main thread. - * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * * @param account The {@link Account} to remove * @param callback Callback to invoke when the request completes, @@ -800,15 +784,16 @@ public class AccountManager { * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)} * instead */ - @RequiresPermission(MANAGE_ACCOUNTS) @Deprecated public AccountManagerFuture<Boolean> removeAccount(final Account account, AccountManagerCallback<Boolean> callback, Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); return new Future2Task<Boolean>(handler, callback) { + @Override public void doWork() throws RemoteException { mService.removeAccount(mResponse, account, false); } + @Override public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { throw new AuthenticatorException("no result in response"); @@ -827,8 +812,8 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * * @param account The {@link Account} to remove * @param activity The {@link Activity} context to use for launching a new @@ -855,11 +840,11 @@ public class AccountManager { * adding accounts (of this type) has been disabled by policy * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> removeAccount(final Account account, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); return new AmsTask(activity, handler, callback) { + @Override public void doWork() throws RemoteException { mService.removeAccount(mResponse, account, activity != null); } @@ -880,9 +865,11 @@ public class AccountManager { if (account == null) throw new IllegalArgumentException("account is null"); if (userHandle == null) throw new IllegalArgumentException("userHandle is null"); return new Future2Task<Boolean>(handler, callback) { + @Override public void doWork() throws RemoteException { mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier()); } + @Override public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { throw new AuthenticatorException("no result in response"); @@ -918,17 +905,14 @@ public class AccountManager { * in which case the account will not be deleted. * <p> * It is safe to call this method from the main thread. - * <p> - * This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the - * same UID or signature as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * * @param account The {@link Account} to delete. * @return True if the account was successfully deleted, false if the * account did not exist, the account is null, or another error * occurs. */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean removeAccountExplicitly(Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -948,14 +932,9 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or - * {@link android.Manifest.permission#USE_CREDENTIALS} - * * @param accountType The account type of the auth token to invalidate, must not be null * @param authToken The auth token to invalidate, may be null */ - @RequiresPermission(anyOf = {MANAGE_ACCOUNTS, USE_CREDENTIALS}) public void invalidateAuthToken(final String accountType, final String authToken) { if (accountType == null) throw new IllegalArgumentException("accountType is null"); try { @@ -976,16 +955,15 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * - * @param account The account to fetch an auth token for - * @param authTokenType The type of auth token to fetch, see {#getAuthToken} + * @param account The account for which an auth token is to be fetched. Cannot be {@code null}. + * @param authTokenType The type of auth token to fetch. Cannot be {@code null}. * @return The cached auth token for this account and type, or null if * no auth token is cached or the account does not exist. + * @see #getAuthToken */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String peekAuthToken(final Account account, final String authTokenType) { if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); @@ -1005,14 +983,12 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * - * @param account The account to set a password for + * @param account The account whose password is to be set. Cannot be {@code null}. * @param password The password to set, null to clear the password */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setPassword(final Account account, final String password) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -1030,14 +1006,14 @@ public class AccountManager { * permissions, and may be used by applications or management interfaces * to "sign out" from an account. * - * <p>It is safe to call this method from the main thread. + * <p>This method only successfully clear the account's password when the + * caller has the same signature as the authenticator that owns the + * specified account. Otherwise, this method will silently fail. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS} + * <p>It is safe to call this method from the main thread. * * @param account The account whose password to clear */ - @RequiresPermission(MANAGE_ACCOUNTS) public void clearPassword(final Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -1055,15 +1031,13 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * - * @param account The account to set the userdata for - * @param key The userdata key to set. Must not be null - * @param value The value to set, null to clear this userdata key + * @param account Account whose user data is to be set. Must not be {@code null}. + * @param key String user data key to set. Must not be null + * @param value String value to set, {@code null} to clear this user data key */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setUserData(final Account account, final String key, final String value) { if (account == null) throw new IllegalArgumentException("account is null"); if (key == null) throw new IllegalArgumentException("key is null"); @@ -1083,15 +1057,13 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} - * and to have the same UID as the account's authenticator. + * <p>This method requires the caller to have a signature match with the + * authenticator that manages the specified account. * * @param account The account to set an auth token for * @param authTokenType The type of the auth token, see {#getAuthToken} * @param authToken The auth token to add to the cache */ - @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setAuthToken(Account account, final String authTokenType, final String authToken) { if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); @@ -1110,9 +1082,6 @@ public class AccountManager { * <p>This method may block while a network request completes, and must * never be made from the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#USE_CREDENTIALS}. - * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()} * @param notifyAuthFailure If true, display a notification and return null @@ -1126,7 +1095,6 @@ public class AccountManager { * @throws java.io.IOException if the authenticator experienced an I/O problem * creating a new auth token, usually because of network trouble */ - @RequiresPermission(USE_CREDENTIALS) public String blockingGetAuthToken(Account account, String authTokenType, boolean notifyAuthFailure) throws OperationCanceledException, IOException, AuthenticatorException { @@ -1165,9 +1133,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#USE_CREDENTIALS}. - * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1201,7 +1166,6 @@ public class AccountManager { * authenticator-dependent. The caller should verify the validity of the * account before requesting an auth token. */ - @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle options, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { @@ -1253,9 +1217,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#USE_CREDENTIALS}. - * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1292,7 +1253,6 @@ public class AccountManager { * boolean, AccountManagerCallback, android.os.Handler)} instead */ @Deprecated - @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final boolean notifyAuthFailure, @@ -1333,9 +1293,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#USE_CREDENTIALS}. - * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1371,7 +1328,6 @@ public class AccountManager { * authenticator-dependent. The caller should verify the validity of the * account before requesting an auth token. */ - @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle options, final boolean notifyAuthFailure, @@ -1401,9 +1357,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. - * * @param accountType The type of account to add; must not be null * @param authTokenType The type of auth token (see {@link #getAuthToken}) * this account will need to be able to generate, null for none @@ -1441,7 +1394,6 @@ public class AccountManager { * creating a new account, usually because of network trouble * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, @@ -1586,9 +1538,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. - * * @param account The account to confirm password knowledge for * @param options Authenticator-specific options for the request; * if the {@link #KEY_PASSWORD} string field is present, the @@ -1615,11 +1564,11 @@ public class AccountManager { * If no activity or password was specified, the returned Bundle contains * {@link #KEY_INTENT} with the {@link Intent} needed to launch the * password prompt. - * + * * <p>Also the returning Bundle may contain {@link * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the * credential was validated/created. - * + * * If an error occurred,{@link AccountManagerFuture#getResult()} throws: * <ul> * <li> {@link AuthenticatorException} if the authenticator failed to respond @@ -1629,7 +1578,6 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Bundle options, final Activity activity, @@ -1668,9 +1616,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. - * * @param account The account to update credentials for * @param authTokenType The credentials entered must allow an auth token * of this type to be created (but no actual auth token is returned); @@ -1706,7 +1651,6 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType, final Bundle options, final Activity activity, @@ -1729,8 +1673,8 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * <p>This method requires the caller to have the same signature as the + * authenticator associated with the specified account type. * * @param accountType The account type associated with the authenticator * to adjust @@ -1758,7 +1702,6 @@ public class AccountManager { * updating settings, usually because of network trouble * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity, final AccountManagerCallback<Bundle> callback, final Handler handler) { @@ -2253,9 +2196,6 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to hold the permission - * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. - * * @param accountType The account type required * (see {@link #getAccountsByType}), must not be null * @param authTokenType The desired auth token type @@ -2292,7 +2232,6 @@ public class AccountManager { * updating settings, usually because of network trouble * </ul> */ - @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> getAuthTokenByFeatures( final String accountType, final String authTokenType, final String[] features, final Activity activity, final Bundle addAccountOptions, diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index da345a6..b65593d 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2812,7 +2812,9 @@ public class ActivityManager { * continues running even if the process is killed and restarted. To remove the watch, * use {@link #clearWatchHeapLimit()}. * - * <p>This API only work if running on a debuggable (userdebug or eng) build.</p> + * <p>This API only work if the calling process has been marked as + * {@link ApplicationInfo#FLAG_DEBUGGABLE} or this is running on a debuggable + * (userdebug or eng) build.</p> * * <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly * handle heap limit reports themselves.</p> diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 5e7bd0d..9ea1606 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -142,13 +142,22 @@ public class AlarmManager { public static final int FLAG_ALLOW_WHILE_IDLE = 1<<2; /** + * Flag for alarms: same as {@link #FLAG_ALLOW_WHILE_IDLE}, but doesn't have restrictions + * on how frequently it can be scheduled. Only available (and automatically applied) to + * system alarms. + * + * @hide + */ + public static final int FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED = 1<<3; + + /** * Flag for alarms: this alarm marks the point where we would like to come out of idle * mode. It may be moved by the alarm manager to match the first wake-from-idle alarm. * Scheduling an alarm with this flag puts the alarm manager in to idle mode, where it * avoids scheduling any further alarms until the marker alarm is executed. * @hide */ - public static final int FLAG_IDLE_UNTIL = 1<<3; + public static final int FLAG_IDLE_UNTIL = 1<<4; private final IAlarmManager mService; private final boolean mAlwaysExact; @@ -565,6 +574,12 @@ public class AlarmManager { * of the device when idle (and thus cause significant battery blame to the app scheduling * them), so they should be used with care. * + * <p>To reduce abuse, there are restrictions on how frequently these alarms will go off + * for a particular application. Under normal system operation, it will not dispatch these + * alarms more than about every minute (at which point every such pending alarm is + * dispatched); when in low-power idle modes this duration may be significantly longer, + * such as 15 minutes.</p> + * * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen * out of order with any other alarms, even those from the same app. This will clearly happen * when the device is idle (since this alarm can go off while idle, when any other alarms @@ -608,6 +623,12 @@ public class AlarmManager { * of the device when idle (and thus cause significant battery blame to the app scheduling * them), so they should be used with care. * + * <p>To reduce abuse, there are restrictions on how frequently these alarms will go off + * for a particular application. Under normal system operation, it will not dispatch these + * alarms more than about every minute (at which point every such pending alarm is + * dispatched); when in low-power idle modes this duration may be significantly longer, + * such as 15 minutes.</p> + * * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen * out of order with any other alarms, even those from the same app. This will clearly happen * when the device is idle (since this alarm can go off while idle, when any other alarms diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index 173b237..0df9ce5 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -35,6 +35,7 @@ public class AssistContent { private Intent mIntent; private ClipData mClipData; private Uri mUri; + private final Bundle mExtras; /** * @hide @@ -53,6 +54,7 @@ public class AssistContent { } public AssistContent() { + mExtras = new Bundle(); } /** @@ -143,6 +145,13 @@ public class AssistContent { return mUri; } + /** + * Return Bundle for extra vendor-specific data that can be modified and examined. + */ + public Bundle getExtras() { + return mExtras; + } + /** @hide */ public AssistContent(Parcel in) { if (in.readInt() != 0) { @@ -155,6 +164,7 @@ public class AssistContent { mUri = Uri.CREATOR.createFromParcel(in); } mIsAppProvidedIntent = in.readInt() == 1; + mExtras = in.readBundle(); } /** @hide */ @@ -178,5 +188,6 @@ public class AssistContent { dest.writeInt(0); } dest.writeInt(mIsAppProvidedIntent ? 1 : 0); + dest.writeBundle(mExtras); } } diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index 0f69817..7f6dae5 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -131,6 +131,7 @@ public class AssistStructure { final int mWidth; final int mHeight; final CharSequence mTitle; + final int mDisplayId; final ViewNode mRoot; WindowNode(AssistStructure assist, ViewRootImpl root) { @@ -142,6 +143,7 @@ public class AssistStructure { mWidth = rect.width(); mHeight = rect.height(); mTitle = root.getTitle(); + mDisplayId = root.getDisplayId(); mRoot = new ViewNode(); ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false); if ((root.getWindowFlags()&WindowManager.LayoutParams.FLAG_SECURE) != 0) { @@ -160,6 +162,7 @@ public class AssistStructure { mWidth = in.readInt(); mHeight = in.readInt(); mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mDisplayId = in.readInt(); mRoot = new ViewNode(in, preader); } @@ -169,29 +172,58 @@ public class AssistStructure { out.writeInt(mWidth); out.writeInt(mHeight); TextUtils.writeToParcel(mTitle, out, 0); + out.writeInt(mDisplayId); mRoot.writeToParcel(out, pwriter); } + /** + * Returns the left edge of the window, in pixels, relative to the left + * edge of the screen. + */ public int getLeft() { return mX; } + /** + * Returns the top edge of the window, in pixels, relative to the top + * edge of the screen. + */ public int getTop() { return mY; } + /** + * Returns the total width of the window in pixels. + */ public int getWidth() { return mWidth; } + /** + * Returns the total height of the window in pixels. + */ public int getHeight() { return mHeight; } + /** + * Returns the title associated with the window, if it has one. + */ public CharSequence getTitle() { return mTitle; } + /** + * Returns the ID of the display this window is on, for use with + * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}. + */ + public int getDisplayId() { + return mDisplayId; + } + + /** + * Returns the {@link ViewNode} containing the root content of the window. + */ public ViewNode getRootViewNode() { return mRoot; } @@ -325,146 +357,288 @@ public class AssistStructure { } } + /** + * Returns the ID associated with this view, as per {@link View#getId() View.getId()}. + */ public int getId() { return mId; } + /** + * If {@link #getId()} is a resource identifier, this is the package name of that + * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} + * for more information. + */ public String getIdPackage() { return mIdPackage; } + /** + * If {@link #getId()} is a resource identifier, this is the type name of that + * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} + * for more information. + */ public String getIdType() { return mIdType; } + /** + * If {@link #getId()} is a resource identifier, this is the entry name of that + * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} + * for more information. + */ public String getIdEntry() { return mIdEntry; } + /** + * Returns the left edge of this view, in pixels, relative to the left edge of its parent. + */ public int getLeft() { return mX; } + /** + * Returns the top edge of this view, in pixels, relative to the top edge of its parent. + */ public int getTop() { return mY; } + /** + * Returns the current X scroll offset of this view, as per + * {@link android.view.View#getScrollX() View.getScrollX()}. + */ public int getScrollX() { return mScrollX; } + /** + * Returns the current Y scroll offset of this view, as per + * {@link android.view.View#getScrollX() View.getScrollY()}. + */ public int getScrollY() { return mScrollY; } + /** + * Returns the width of this view, in pixels. + */ public int getWidth() { return mWidth; } + /** + * Returns the height of this view, in pixels. + */ public int getHeight() { return mHeight; } + /** + * Returns the visibility mode of this view, as per + * {@link android.view.View#getVisibility() View.getVisibility()}. + */ public int getVisibility() { return mFlags&ViewNode.FLAGS_VISIBILITY_MASK; } + /** + * Returns true if assist data has been blocked starting at this node in the hierarchy. + */ public boolean isAssistBlocked() { return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0; } + /** + * Returns true if this node is in an enabled state. + */ public boolean isEnabled() { return (mFlags&ViewNode.FLAGS_DISABLED) == 0; } + /** + * Returns true if this node is clickable by the user. + */ public boolean isClickable() { return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0; } + /** + * Returns true if this node can take input focus. + */ public boolean isFocusable() { return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0; } + /** + * Returns true if this node currently had input focus at the time that the + * structure was collected. + */ public boolean isFocused() { return (mFlags&ViewNode.FLAGS_FOCUSED) != 0; } + /** + * Returns true if this node currently had accessibility focus at the time that the + * structure was collected. + */ public boolean isAccessibilityFocused() { return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0; } + /** + * Returns true if this node represents something that is checkable by the user. + */ public boolean isCheckable() { return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0; } + /** + * Returns true if this node is currently in a checked state. + */ public boolean isChecked() { return (mFlags&ViewNode.FLAGS_CHECKED) != 0; } + /** + * Returns true if this node has currently been selected by the user. + */ public boolean isSelected() { return (mFlags&ViewNode.FLAGS_SELECTED) != 0; } + /** + * Returns true if this node has currently been activated by the user. + */ public boolean isActivated() { return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0; } + /** + * Returns true if this node is something the user can perform a long click/press on. + */ public boolean isLongClickable() { return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0; } + /** + * Returns true if this node is something the user can perform a context click on. + */ public boolean isContextClickable() { return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0; } + /** + * Returns the class name of the node's implementation, indicating its behavior. + * For example, a button will report "android.widget.Button" meaning it behaves + * like a {@link android.widget.Button}. + */ public String getClassName() { return mClassName; } + /** + * Returns any content description associated with the node, which semantically describes + * its purpose for accessibility and other uses. + */ public CharSequence getContentDescription() { return mContentDescription; } + /** + * Returns any text associated with the node that is displayed to the user, or null + * if there is none. + */ public CharSequence getText() { return mText != null ? mText.mText : null; } + /** + * If {@link #getText()} is non-null, this is where the current selection starts. + */ public int getTextSelectionStart() { return mText != null ? mText.mTextSelectionStart : -1; } + /** + * If {@link #getText()} is non-null, this is where the current selection starts. + * If there is no selection, returns the same value as {@link #getTextSelectionStart()}, + * indicating the cursor position. + */ public int getTextSelectionEnd() { return mText != null ? mText.mTextSelectionEnd : -1; } + /** + * If {@link #getText()} is non-null, this is the main text color associated with it. + * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned. + * Note that the text may also contain style spans that modify the color of specific + * parts of the text. + */ public int getTextColor() { return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED; } + /** + * If {@link #getText()} is non-null, this is the main text background color associated + * with it. + * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned. + * Note that the text may also contain style spans that modify the color of specific + * parts of the text. + */ public int getTextBackgroundColor() { return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED; } + /** + * If {@link #getText()} is non-null, this is the main text size (in pixels) associated + * with it. + * Note that the text may also contain style spans that modify the size of specific + * parts of the text. + */ public float getTextSize() { return mText != null ? mText.mTextSize : 0; } + /** + * If {@link #getText()} is non-null, this is the main text style associated + * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD}, + * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or + * {@link #TEXT_STYLE_UNDERLINE}. + * Note that the text may also contain style spans that modify the style of specific + * parts of the text. + */ public int getTextStyle() { return mText != null ? mText.mTextStyle : 0; } + /** + * Return additional hint text associated with the node; this is typically used with + * a node that takes user input, describing to the user what the input means. + */ public String getHint() { return mText != null ? mText.mHint : null; } + /** + * Return a Bundle containing optional vendor-specific extension information. + */ public Bundle getExtras() { return mExtras; } + /** + * Return the number of children this node has. + */ public int getChildCount() { return mChildren != null ? mChildren.length : 0; } + /** + * Return a child of this node, given an index value from 0 to + * {@link #getChildCount()}-1. + */ public ViewNode getChildAt(int index) { return mChildren[index]; } @@ -663,6 +837,19 @@ public class AssistStructure { } @Override + public int addChildCount(int num) { + if (mNode.mChildren == null) { + setChildCount(num); + return 0; + } + final int start = mNode.mChildren.length; + ViewNode[] newArray = new ViewNode[start + num]; + System.arraycopy(mNode.mChildren, 0, newArray, 0, start); + mNode.mChildren = newArray; + return start; + } + + @Override public int getChildCount() { return mNode.mChildren != null ? mNode.mChildren.length : 0; } @@ -801,6 +988,9 @@ public class AssistStructure { return assistBundle.getParcelable(ASSIST_KEY); } + /** + * Return the activity this AssistStructure came from. + */ public ComponentName getActivityComponent() { ensureData(); return mActivityComponent; diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 2ed8b0f..5327646 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -418,7 +418,7 @@ public class DownloadManager { private int mNotificationVisibility = VISIBILITY_VISIBLE; /** - * @param uri the HTTP URI to download. + * @param uri the HTTP or HTTPS URI to download. */ public Request(Uri uri) { if (uri == null) { diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 9604789..c2bf28a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -55,6 +55,7 @@ import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; +import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -166,6 +167,7 @@ public final class LoadedApk { if (runtimeIsa.equals(secondaryIsa)) { final ApplicationInfo modified = new ApplicationInfo(info); modified.nativeLibraryDir = modified.secondaryNativeLibraryDir; + modified.primaryCpuAbi = modified.secondaryCpuAbi; return modified; } } @@ -272,8 +274,9 @@ public final class LoadedApk { } } - final ArrayList<String> zipPaths = new ArrayList<>(); - final ArrayList<String> libPaths = new ArrayList<>(); + final List<String> zipPaths = new ArrayList<>(); + final List<String> apkPaths = new ArrayList<>(); + final List<String> libPaths = new ArrayList<>(); if (mRegisterPackage) { try { @@ -329,6 +332,8 @@ public final class LoadedApk { } } + apkPaths.addAll(zipPaths); + if (mSharedLibraries != null) { for (String lib : mSharedLibraries) { if (!zipPaths.contains(lib)) { @@ -346,6 +351,14 @@ public final class LoadedApk { } final String zip = TextUtils.join(File.pathSeparator, zipPaths); + + // Add path to libraries in apk for current abi + if (mApplicationInfo.primaryCpuAbi != null) { + for (String apk : apkPaths) { + libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi); + } + } + final String lib = TextUtils.join(File.pathSeparator, libPaths); /* diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 96c6878..33a47b2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1331,11 +1331,14 @@ public class Notification implements Parcelable public Notification(Context context, int icon, CharSequence tickerText, long when, CharSequence contentTitle, CharSequence contentText, Intent contentIntent) { - this.when = when; - this.icon = icon; - this.tickerText = tickerText; - setLatestEventInfo(context, contentTitle, contentText, - PendingIntent.getActivity(context, 0, contentIntent, 0)); + new Builder(context) + .setWhen(when) + .setSmallIcon(icon) + .setTicker(tickerText) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0)) + .buildInto(this); } /** diff --git a/core/java/android/app/admin/DeviceInitializerStatus.java b/core/java/android/app/admin/DeviceInitializerStatus.java deleted file mode 100644 index 7de518b..0000000 --- a/core/java/android/app/admin/DeviceInitializerStatus.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.admin; - -/** - * Defines constants designating device provisioning status used with {@link - * android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}. - * - * This class contains flag constants that define special status codes: - * <ul> - * <li>{@link #FLAG_STATUS_ERROR} is used to define provisioning error status codes - * <li>{@link #FLAG_STATUS_CUSTOM} is used to define custom status codes - * <li>{@link #FLAG_STATUS_HIGH_PRIORITY} is used to define high priority status codes - * </ul> - * - * <p>Status codes used by ManagedProvisioning are also defined in this class. These status codes - * include provisioning errors and status codes. - * <ul> - * <li>{@link #STATUS_ERROR_CONNECT_WIFI} - * <li>{@link #STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING} - * <li>{@link #STATUS_ERROR_DOWNLOAD_PACKAGE} - * <li>{@link #STATUS_ERROR_INSTALL_PACKAGE} - * <li>{@link #STATUS_ERROR_SET_DEVICE_POLICY} - * <li>{@link #STATUS_ERROR_DELETE_APPS} - * <li>{@link #STATUS_ERROR_DOUBLE_BUMP} - * <li>{@link #STATUS_STATE_CONNECTING_BLUETOOTH_PROXY} - * <li>{@link #STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY} - * <li>{@link #STATUS_STATE_DEVICE_PROVISIONED} - * </ul> - */ -public class DeviceInitializerStatus { - /** - * A flag used to designate an error status. - * - * <p>This flag is used with {@code statusCode} values sent through - * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)} - * @see #isErrorStatus(int) - */ - public static final int FLAG_STATUS_ERROR = 0x01000000; - - /** - * A flag used to designate a custom status. Custom status codes will be defined by device - * initializer agents. - * - * <p>This flag is used with {@code statusCode} values sent through - * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)} - * @see #isCustomStatus(int) - */ - public static final int FLAG_STATUS_CUSTOM = 0x02000000; - - /** - * A bit flag used to designate a reserved status. Reserved status codes will not be defined - * in AOSP. - * - * <p>This flag is used with {@code statusCode} values sent through - * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)} - */ - public static final int FLAG_STATUS_RESERVED = 0x04000000; - - /** - * A flag used to indicate that a status message is high priority. - * - * <p>This flag is used with {@code statusCode} values sent through - * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)} - * @see #isHighPriority(int) - */ - public static final int FLAG_STATUS_HIGH_PRIORITY = 0x08000000; - - /** - * Device provisioning status code that indicates that a device is connecting to establish - * a Bluetooth network proxy. - */ - public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 8; - - /** - * Device provisioning status code that indicates that a connected Bluetooth network proxy - * is being shut down. - */ - public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 9; - - /** - * Device provisioning status code that indicates that a device has been successfully - * provisioned. - */ - public static final int STATUS_STATE_DEVICE_PROVISIONED = FLAG_STATUS_HIGH_PRIORITY | 10; - - /** - * Device provisioning error status code that indicates that a device could not connect to - * a Wi-Fi network. - */ - public static final int STATUS_ERROR_CONNECT_WIFI = FLAG_STATUS_ERROR | 21; - - /** - * Device provisioning error status indicating that factory reset protection is enabled on - * the provisioned device and cannot be disabled with the provided data. - */ - public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = - FLAG_STATUS_ERROR | 22; - - /** - * Device provisioning error status indicating that device administrator and device initializer - * packages could not be downloaded and verified successfully. - */ - public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = FLAG_STATUS_ERROR | 23; - - /** - * Device provisioning error status indicating that device owner and device initializer packages - * could not be installed. - */ - public static final int STATUS_ERROR_INSTALL_PACKAGE = FLAG_STATUS_ERROR | 24; - - /** - * Device provisioning error status indicating that the device owner or device initializer - * components could not be set. - */ - public static final int STATUS_ERROR_SET_DEVICE_POLICY = FLAG_STATUS_ERROR | 25; - - /** - * Device provisioning error status indicating that deleting non-required applications during - * provisioning failed. - */ - public static final int STATUS_ERROR_DELETE_APPS = FLAG_STATUS_ERROR | 26; - - /** - * Device provisioning error status code that indicates that a provisioning attempt has failed - * because the device has already been provisioned or that provisioning has already started. - */ - public static final int STATUS_ERROR_DOUBLE_BUMP = FLAG_STATUS_ERROR | 30; - - private DeviceInitializerStatus() {} -} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index e5ed150..9f49154 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -149,6 +149,7 @@ public class DevicePolicyManager { * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li> * <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li> * </ul> * * <p> When device owner provisioning has completed, an intent of the type @@ -163,14 +164,19 @@ public class DevicePolicyManager { = "android.app.action.PROVISION_MANAGED_DEVICE"; /** - * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows - * a mobile device management application that starts managed profile provisioning to pass data - * to itself on the managed profile when provisioning completes. The mobile device management - * application sends this extra in an intent with the action - * {@link #ACTION_PROVISION_MANAGED_PROFILE} and receives it in + * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that + * allows a mobile device management application which starts managed provisioning to pass data + * to itself. + * <p> + * If used with {@link #ACTION_PROVISION_MANAGED_PROFILE} it can be used by the application that + * sends the intent to pass data to itself on the newly created profile. + * If used with {@link #ACTION_PROVISION_MANAGED_DEVICE} it allows passing data to the same + * instance of the app on the primary user. + * <p> + * In both cases the application receives the data in * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed - * during the managed profile provisioning. + * during the managed provisioning. */ public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; @@ -400,7 +406,7 @@ public class DevicePolicyManager { * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * - * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM} should be + * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be * present. The provided checksum should match the checksum of the file at the download * location. If the checksum doesn't match an error will be shown to the user and the user will * be asked to factory reset the device. @@ -412,24 +418,24 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the + * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * - * <p>The certificates of an android package archive can be obtained using + * <p>The signatures of an android package archive can be obtained using * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag * {@link android.content.pm.PackageManager#GET_SIGNATURES}. * * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} should be - * present. The provided checksum should match the checksum of any certificate of the file at + * present. The provided checksum should match the checksum of any signature of the file at * the download location. If the checksum does not match an error will be shown to the user and * the user will be asked to factory reset the device. * * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner * provisioning via an NFC bump. */ - public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM - = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM"; + public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM"; /** * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile @@ -508,7 +514,7 @@ public class DevicePolicyManager { * location specified in * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * - * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM} + * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM} * should be present. The provided checksum should match the checksum of the file at the * download location. If the checksum doesn't match an error will be shown to the user and the * user will be asked to factory reset the device. @@ -520,68 +526,24 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the + * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * - * <p>The certificates of an android package archive can be obtained using + * <p>The signatures of an android package archive can be obtained using * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag * {@link android.content.pm.PackageManager#GET_SIGNATURES}. * * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM} - * should be present. The provided checksum should match the checksum of any certificate of the + * should be present. The provided checksum should match the checksum of any signature of the * file at the download location. If the checksum doesn't match an error will be shown to the * user and the user will be asked to factory reset the device. * * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner * provisioning via an NFC bump. */ - public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM - = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM"; - - /** - * A String extra holding the MAC address of the Bluetooth device to connect to with status - * updates during provisioning. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS - = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS"; - - /** - * A String extra holding the Bluetooth service UUID on the device to connect to with status - * updates during provisioning. - * - * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_BT_UUID - = "android.app.extra.PROVISIONING_BT_UUID"; - - /** - * A String extra holding a unique identifier used to identify the device connecting over - * Bluetooth. This identifier will be part of every status message sent to the remote device. - * - * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_BT_DEVICE_ID - = "android.app.extra.PROVISIONING_BT_DEVICE_ID"; - - /** - * A Boolean extra that that will cause a provisioned device to temporarily proxy network - * traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_BT_USE_PROXY - = "android.app.extra.PROVISIONING_BT_USE_PROXY"; + public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM + = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM"; /** * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that @@ -665,11 +627,7 @@ public class DevicePolicyManager { * Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property * should be converted to a String via * {@link android.content.ComponentName#flattenToString()}</li> - * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li> - * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li> - * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li> - * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li> - * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li></ul> * * <p> When device owner provisioning has completed, an intent of the type * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the @@ -727,45 +685,6 @@ public class DevicePolicyManager { = "android.app.action.SET_PROFILE_OWNER"; /** - * Protected broadcast action that will be sent to managed provisioning to notify it that a - * status update has been reported by the device initializer. The status update will be - * reported to the remote setup device over Bluetooth. - * - * <p>Broadcasts with this action must supply a - * {@linkplain DeviceInitializerStatus#FLAG_STATUS_CUSTOM custom} status code in the - * {@link EXTRA_DEVICE_INITIALIZER_STATUS_CODE} extra. - * - * <p>Broadcasts may optionally contain a description in the - * {@link EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION} extra. - * @hide - */ - @SystemApi - public static final String ACTION_SEND_DEVICE_INITIALIZER_STATUS - = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS"; - - /** - * An integer extra that contains the status code that defines a status update. This extra must - * sent as part of a broadcast with an action of {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}. - * - * <p>The status code sent with this extra must be a custom status code as defined by - * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}. - * @hide - */ - @SystemApi - public static final String EXTRA_DEVICE_INITIALIZER_STATUS_CODE - = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE"; - - /** - * A {@code String} extra that contains an optional description accompanying a status update. - * This extra my be sent as part of a broadcast with an action of - * {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}. - * @hide - */ - @SystemApi - public static final String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION - = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION"; - - /** * @hide * Name of the profile owner admin that controls the user. */ @@ -4291,21 +4210,6 @@ public class DevicePolicyManager { } /** - * Called by device initializer to send a provisioning status update to the remote setup device. - * - * @param statusCode a custom status code value as defined by - * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}. - * @param description custom description of the status code sent - */ - public void sendDeviceInitializerStatus(int statusCode, String description) { - try { - mService.sendDeviceInitializerStatus(statusCode, description); - } catch (RemoteException re) { - Log.w(TAG, "Could not send device initializer status", re); - } - } - - /** * Called by device owners to set a local system update policy. When a new policy is set, * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index a700806..376a3d8 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -220,7 +220,6 @@ interface IDevicePolicyManager { void setUserIcon(in ComponentName admin, in Bitmap icon); - void sendDeviceInitializerStatus(int statusCode, String description); void setSystemUpdatePolicy(in ComponentName who, in SystemUpdatePolicy policy); SystemUpdatePolicy getSystemUpdatePolicy(); diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 58279d7..369b692 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -68,9 +68,15 @@ public final class UsageEvents implements Parcelable { public static final int CONFIGURATION_CHANGE = 5; /** - * An event type denoting that a package was interacted with in some way. + * An event type denoting that a package was interacted with in some way by the system. + * @hide */ - public static final int INTERACTION = 6; + public static final int SYSTEM_INTERACTION = 6; + + /** + * An event type denoting that a package was interacted with in some way by the user. + */ + public static final int USER_INTERACTION = 7; /** * {@hide} diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 81c7422..0fce4e2 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -41,11 +41,19 @@ public final class UsageStats implements Parcelable { public long mEndTimeStamp; /** + * Last time used by the user with an explicit action (notification, activity launch). * {@hide} */ public long mLastTimeUsed; /** + * The last time the package was used via implicit, non-user initiated actions (service + * was bound, etc). + * {@hide} + */ + public long mLastTimeSystemUsed; + + /** * Last time the package was used and the beginning of the idle countdown. * This uses a different timebase that is about how much the device has been in use in general. * {@hide} @@ -82,6 +90,7 @@ public final class UsageStats implements Parcelable { mLaunchCount = stats.mLaunchCount; mLastEvent = stats.mLastEvent; mBeginIdleTime = stats.mBeginIdleTime; + mLastTimeSystemUsed = stats.mLastTimeSystemUsed; } public String getPackageName() { @@ -119,6 +128,16 @@ public final class UsageStats implements Parcelable { /** * @hide + * Get the last time this package was used by the system (not the user). This can be different + * from {@link #getLastTimeUsed()} when the system binds to one of this package's services. + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeSystemUsed() { + return mLastTimeSystemUsed; + } + + /** + * @hide * Get the last time this package was active, measured in milliseconds. This timestamp * uses a timebase that represents how much the device was used and not wallclock time. */ @@ -151,6 +170,7 @@ public final class UsageStats implements Parcelable { mEndTimeStamp = right.mEndTimeStamp; mLastTimeUsed = right.mLastTimeUsed; mBeginIdleTime = right.mBeginIdleTime; + mLastTimeSystemUsed = right.mLastTimeSystemUsed; } mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp); mTotalTimeInForeground += right.mTotalTimeInForeground; @@ -172,6 +192,7 @@ public final class UsageStats implements Parcelable { dest.writeInt(mLaunchCount); dest.writeInt(mLastEvent); dest.writeLong(mBeginIdleTime); + dest.writeLong(mLastTimeSystemUsed); } public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() { @@ -186,6 +207,7 @@ public final class UsageStats implements Parcelable { stats.mLaunchCount = in.readInt(); stats.mLastEvent = in.readInt(); stats.mBeginIdleTime = in.readLong(); + stats.mLastTimeSystemUsed = in.readLong(); return stats; } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index e916b9f..d4c4437 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -19,6 +19,7 @@ package android.content; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.pm.PathPermission; @@ -635,7 +636,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * {@link #onCreate} has been called -- this will return {@code null} in the * constructor. */ - public final Context getContext() { + public final @Nullable Context getContext() { return mContext; } @@ -663,7 +664,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @throws SecurityException if the calling package doesn't belong to the * calling UID. */ - public final String getCallingPackage() { + public final @Nullable String getCallingPackage() { final String pkg = mCallingPackage.get(); if (pkg != null) { mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); @@ -712,7 +713,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param permission Name of the permission required for read-only access. */ - protected final void setReadPermission(String permission) { + protected final void setReadPermission(@Nullable String permission) { mReadPermission = permission; } @@ -723,7 +724,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes * and Threads</a>. */ - public final String getReadPermission() { + public final @Nullable String getReadPermission() { return mReadPermission; } @@ -734,7 +735,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param permission Name of the permission required for read/write access. */ - protected final void setWritePermission(String permission) { + protected final void setWritePermission(@Nullable String permission) { mWritePermission = permission; } @@ -745,7 +746,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes * and Threads</a>. */ - public final String getWritePermission() { + public final @Nullable String getWritePermission() { return mWritePermission; } @@ -756,7 +757,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param permissions Array of path permission descriptions. */ - protected final void setPathPermissions(PathPermission[] permissions) { + protected final void setPathPermissions(@Nullable PathPermission[] permissions) { mPathPermissions = permissions; } @@ -767,7 +768,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes * and Threads</a>. */ - public final PathPermission[] getPathPermissions() { + public final @Nullable PathPermission[] getPathPermissions() { return mPathPermissions; } @@ -893,8 +894,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * If {@code null} then the provider is free to define the sort order. * @return a Cursor or {@code null}. */ - public abstract Cursor query(Uri uri, String[] projection, - String selection, String[] selectionArgs, String sortOrder); + public abstract @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder); /** * Implement this to handle query requests from clients with support for cancellation. @@ -959,9 +961,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * when the query is executed. * @return a Cursor or {@code null}. */ - public Cursor query(Uri uri, String[] projection, - String selection, String[] selectionArgs, String sortOrder, - CancellationSignal cancellationSignal) { + public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { return query(uri, projection, selection, selectionArgs, sortOrder); } @@ -983,7 +985,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @param uri the URI to query. * @return a MIME type string, or {@code null} if there is no type. */ - public abstract String getType(Uri uri); + public abstract @Nullable String getType(@NonNull Uri uri); /** * Implement this to support canonicalization of URIs that refer to your @@ -1015,7 +1017,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @return Return the canonical representation of <var>url</var>, or null if * canonicalization of that Uri is not supported. */ - public Uri canonicalize(Uri url) { + public @Nullable Uri canonicalize(@NonNull Uri url) { return null; } @@ -1033,7 +1035,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * the data identified by the canonical representation can not be found in * the current environment. */ - public Uri uncanonicalize(Uri url) { + public @Nullable Uri uncanonicalize(@NonNull Uri url) { return url; } @@ -1066,7 +1068,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * This must not be {@code null}. * @return The URI for the newly inserted item. */ - public abstract Uri insert(Uri uri, ContentValues values); + public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values); /** * Override this to handle requests to insert a set of new rows, or the @@ -1083,7 +1085,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * This must not be {@code null}. * @return The number of values that were inserted. */ - public int bulkInsert(Uri uri, ContentValues[] values) { + public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) { int numValues = values.length; for (int i = 0; i < numValues; i++) { insert(uri, values[i]); @@ -1111,7 +1113,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @return The number of rows affected. * @throws SQLException */ - public abstract int delete(Uri uri, String selection, String[] selectionArgs); + public abstract int delete(@NonNull Uri uri, @Nullable String selection, + @Nullable String[] selectionArgs); /** * Implement this to handle requests to update one or more rows. @@ -1130,8 +1133,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @param selection An optional filter to match rows to update. * @return the number of rows affected. */ - public abstract int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs); + public abstract int update(@NonNull Uri uri, @Nullable ContentValues values, + @Nullable String selection, @Nullable String[] selectionArgs); /** * Override this to handle requests to open a file blob. @@ -1190,7 +1193,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #getType(android.net.Uri) * @see ParcelFileDescriptor#parseMode(String) */ - public ParcelFileDescriptor openFile(Uri uri, String mode) + public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { throw new FileNotFoundException("No files supported by provider at " + uri); @@ -1260,8 +1263,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #getType(android.net.Uri) * @see ParcelFileDescriptor#parseMode(String) */ - public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal) - throws FileNotFoundException { + public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode, + @Nullable CancellationSignal signal) throws FileNotFoundException { return openFile(uri, mode); } @@ -1316,7 +1319,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #openFileHelper(Uri, String) * @see #getType(android.net.Uri) */ - public AssetFileDescriptor openAssetFile(Uri uri, String mode) + public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { ParcelFileDescriptor fd = openFile(uri, mode); return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; @@ -1379,8 +1382,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #openFileHelper(Uri, String) * @see #getType(android.net.Uri) */ - public AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal) - throws FileNotFoundException { + public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode, + @Nullable CancellationSignal signal) throws FileNotFoundException { return openAssetFile(uri, mode); } @@ -1398,8 +1401,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @return Returns a new ParcelFileDescriptor that can be used by the * client to access the file. */ - protected final ParcelFileDescriptor openFileHelper(Uri uri, - String mode) throws FileNotFoundException { + protected final @NonNull ParcelFileDescriptor openFileHelper(@NonNull Uri uri, + @NonNull String mode) throws FileNotFoundException { Cursor c = query(uri, new String[]{"_data"}, null, null, null); int count = (c != null) ? c.getCount() : 0; if (count != 1) { @@ -1445,7 +1448,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #openTypedAssetFile(Uri, String, Bundle) * @see ClipDescription#compareMimeTypes(String, String) */ - public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) { return null; } @@ -1494,8 +1497,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #openAssetFile(Uri, String) * @see ClipDescription#compareMimeTypes(String, String) */ - public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) - throws FileNotFoundException { + public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri, + @NonNull String mimeTypeFilter, @Nullable Bundle opts) throws FileNotFoundException { if ("*/*".equals(mimeTypeFilter)) { // If they can take anything, the untyped open call is good enough. return openAssetFile(uri, "r"); @@ -1561,9 +1564,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @see #openAssetFile(Uri, String) * @see ClipDescription#compareMimeTypes(String, String) */ - public AssetFileDescriptor openTypedAssetFile( - Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal) - throws FileNotFoundException { + public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri, + @NonNull String mimeTypeFilter, @Nullable Bundle opts, + @Nullable CancellationSignal signal) throws FileNotFoundException { return openTypedAssetFile(uri, mimeTypeFilter, opts); } @@ -1585,8 +1588,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @param opts Options supplied by caller. * @param args Your own custom arguments. */ - public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, - Bundle opts, T args); + public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri, + @NonNull String mimeType, @Nullable Bundle opts, @Nullable T args); } /** @@ -1606,9 +1609,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * the pipe. This should be returned to the caller for reading; the caller * is responsible for closing it when done. */ - public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType, - final Bundle opts, final T args, final PipeDataWriter<T> func) - throws FileNotFoundException { + public @NonNull <T> ParcelFileDescriptor openPipeHelper(final @NonNull Uri uri, + final @NonNull String mimeType, final @Nullable Bundle opts, final @Nullable T args, + final @NonNull PipeDataWriter<T> func) throws FileNotFoundException { try { final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); @@ -1713,8 +1716,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @throws OperationApplicationException thrown if any operation fails. * @see ContentProviderOperation#apply */ - public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) - throws OperationApplicationException { + public @NonNull ContentProviderResult[] applyBatch( + @NonNull ArrayList<ContentProviderOperation> operations) + throws OperationApplicationException { final int numOperations = operations.size(); final ContentProviderResult[] results = new ContentProviderResult[numOperations]; for (int i = 0; i < numOperations; i++) { @@ -1741,7 +1745,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * @return provider-defined return value. May be {@code null}, which is also * the default for providers which don't implement any call methods. */ - public Bundle call(String method, @Nullable String arg, @Nullable Bundle extras) { + public @Nullable Bundle call(@NonNull String method, @Nullable String arg, + @Nullable Bundle extras) { return null; } diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index e15ac94..d12595f 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -16,6 +16,8 @@ package android.content; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.net.Uri; @@ -30,6 +32,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; @@ -109,14 +112,19 @@ public class ContentProviderClient { } /** See {@link ContentProvider#query ContentProvider.query} */ - public Cursor query(Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder) throws RemoteException { + public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder) throws RemoteException { return query(url, projection, selection, selectionArgs, sortOrder, null); } /** See {@link ContentProvider#query ContentProvider.query} */ - public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, - String sortOrder, CancellationSignal cancellationSignal) throws RemoteException { + public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) + throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { ICancellationSignal remoteCancellationSignal = null; @@ -138,7 +146,9 @@ public class ContentProviderClient { } /** See {@link ContentProvider#getType ContentProvider.getType} */ - public String getType(Uri url) throws RemoteException { + public @Nullable String getType(@NonNull Uri url) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.getType(url); @@ -153,7 +163,11 @@ public class ContentProviderClient { } /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */ - public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException { + public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) + throws RemoteException { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter"); + beforeRemote(); try { return mContentProvider.getStreamTypes(url, mimeTypeFilter); @@ -168,7 +182,9 @@ public class ContentProviderClient { } /** See {@link ContentProvider#canonicalize} */ - public final Uri canonicalize(Uri url) throws RemoteException { + public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.canonicalize(mPackageName, url); @@ -183,7 +199,9 @@ public class ContentProviderClient { } /** See {@link ContentProvider#uncanonicalize} */ - public final Uri uncanonicalize(Uri url) throws RemoteException { + public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.uncanonicalize(mPackageName, url); @@ -198,7 +216,10 @@ public class ContentProviderClient { } /** See {@link ContentProvider#insert ContentProvider.insert} */ - public Uri insert(Uri url, ContentValues initialValues) throws RemoteException { + public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues) + throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.insert(mPackageName, url, initialValues); @@ -213,7 +234,11 @@ public class ContentProviderClient { } /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */ - public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException { + public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues) + throws RemoteException { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(initialValues, "initialValues"); + beforeRemote(); try { return mContentProvider.bulkInsert(mPackageName, url, initialValues); @@ -228,8 +253,10 @@ public class ContentProviderClient { } /** See {@link ContentProvider#delete ContentProvider.delete} */ - public int delete(Uri url, String selection, String[] selectionArgs) - throws RemoteException { + public int delete(@NonNull Uri url, @Nullable String selection, + @Nullable String[] selectionArgs) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.delete(mPackageName, url, selection, selectionArgs); @@ -244,8 +271,10 @@ public class ContentProviderClient { } /** See {@link ContentProvider#update ContentProvider.update} */ - public int update(Uri url, ContentValues values, String selection, - String[] selectionArgs) throws RemoteException { + public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection, + @Nullable String[] selectionArgs) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + beforeRemote(); try { return mContentProvider.update(mPackageName, url, values, selection, selectionArgs); @@ -266,7 +295,7 @@ public class ContentProviderClient { * you use the {@link ContentResolver#openFileDescriptor * ContentResolver.openFileDescriptor} API instead. */ - public ParcelFileDescriptor openFile(Uri url, String mode) + public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode) throws RemoteException, FileNotFoundException { return openFile(url, mode, null); } @@ -278,8 +307,11 @@ public class ContentProviderClient { * you use the {@link ContentResolver#openFileDescriptor * ContentResolver.openFileDescriptor} API instead. */ - public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal) - throws RemoteException, FileNotFoundException { + public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode, + @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(mode, "mode"); + beforeRemote(); try { ICancellationSignal remoteSignal = null; @@ -306,7 +338,7 @@ public class ContentProviderClient { * you use the {@link ContentResolver#openAssetFileDescriptor * ContentResolver.openAssetFileDescriptor} API instead. */ - public AssetFileDescriptor openAssetFile(Uri url, String mode) + public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode) throws RemoteException, FileNotFoundException { return openAssetFile(url, mode, null); } @@ -318,8 +350,11 @@ public class ContentProviderClient { * you use the {@link ContentResolver#openAssetFileDescriptor * ContentResolver.openAssetFileDescriptor} API instead. */ - public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal) - throws RemoteException, FileNotFoundException { + public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode, + @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(mode, "mode"); + beforeRemote(); try { ICancellationSignal remoteSignal = null; @@ -340,15 +375,19 @@ public class ContentProviderClient { } /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */ - public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, - String mimeType, Bundle opts) throws RemoteException, FileNotFoundException { + public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mimeType, @Nullable Bundle opts) + throws RemoteException, FileNotFoundException { return openTypedAssetFileDescriptor(uri, mimeType, opts, null); } /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */ - public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, - String mimeType, Bundle opts, CancellationSignal signal) - throws RemoteException, FileNotFoundException { + public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal) + throws RemoteException, FileNotFoundException { + Preconditions.checkNotNull(uri, "uri"); + Preconditions.checkNotNull(mimeType, "mimeType"); + beforeRemote(); try { ICancellationSignal remoteSignal = null; @@ -370,8 +409,11 @@ public class ContentProviderClient { } /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */ - public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) - throws RemoteException, OperationApplicationException { + public @NonNull ContentProviderResult[] applyBatch( + @NonNull ArrayList<ContentProviderOperation> operations) + throws RemoteException, OperationApplicationException { + Preconditions.checkNotNull(operations, "operations"); + beforeRemote(); try { return mContentProvider.applyBatch(mPackageName, operations); @@ -386,7 +428,10 @@ public class ContentProviderClient { } /** See {@link ContentProvider#call(String, String, Bundle)} */ - public Bundle call(String method, String arg, Bundle extras) throws RemoteException { + public @Nullable Bundle call(@NonNull String method, @Nullable String arg, + @Nullable Bundle extras) throws RemoteException { + Preconditions.checkNotNull(method, "method"); + beforeRemote(); try { return mContentProvider.call(mPackageName, method, arg, extras); @@ -436,7 +481,7 @@ public class ContentProviderClient { * @return If the associated {@link ContentProvider} is local, returns it. * Otherwise returns null. */ - public ContentProvider getLocalContentProvider() { + public @Nullable ContentProvider getLocalContentProvider() { return ContentProvider.coerceToLocalContentProvider(mContentProvider); } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 96a80e7..057001c 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -17,6 +17,7 @@ package android.content; import android.accounts.Account; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerNative; import android.app.ActivityThread; @@ -47,6 +48,8 @@ import android.util.Log; import dalvik.system.CloseGuard; +import com.android.internal.util.Preconditions; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -320,7 +323,9 @@ public abstract class ContentResolver { * using the content:// scheme. * @return A MIME type for the content, or null if the URL is invalid or the type is unknown */ - public final String getType(Uri url) { + public final @Nullable String getType(@NonNull Uri url) { + Preconditions.checkNotNull(url, "url"); + // XXX would like to have an acquireExistingUnstableProvider for this. IContentProvider provider = acquireExistingProvider(url); if (provider != null) { @@ -371,7 +376,10 @@ public abstract class ContentResolver { * data streams that match the given mimeTypeFilter. If there are none, * null is returned. */ - public String[] getStreamTypes(Uri url, String mimeTypeFilter) { + public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter"); + IContentProvider provider = acquireProvider(url); if (provider == null) { return null; @@ -418,8 +426,9 @@ public abstract class ContentResolver { * @return A Cursor object, which is positioned before the first entry, or null * @see Cursor */ - public final Cursor query(Uri uri, String[] projection, - String selection, String[] selectionArgs, String sortOrder) { + public final @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder) { return query(uri, projection, selection, selectionArgs, sortOrder, null); } @@ -457,9 +466,10 @@ public abstract class ContentResolver { * @return A Cursor object, which is positioned before the first entry, or null * @see Cursor */ - public final Cursor query(final Uri uri, String[] projection, - String selection, String[] selectionArgs, String sortOrder, - CancellationSignal cancellationSignal) { + public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection, + @Nullable String selection, @Nullable String[] selectionArgs, + @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { + Preconditions.checkNotNull(uri, "uri"); IContentProvider unstableProvider = acquireUnstableProvider(uri); if (unstableProvider == null) { return null; @@ -555,7 +565,8 @@ public abstract class ContentResolver { * * @see #uncanonicalize */ - public final Uri canonicalize(Uri url) { + public final @Nullable Uri canonicalize(@NonNull Uri url) { + Preconditions.checkNotNull(url, "url"); IContentProvider provider = acquireProvider(url); if (provider == null) { return null; @@ -590,7 +601,8 @@ public abstract class ContentResolver { * * @see #canonicalize */ - public final Uri uncanonicalize(Uri url) { + public final @Nullable Uri uncanonicalize(@NonNull Uri url) { + Preconditions.checkNotNull(url, "url"); IContentProvider provider = acquireProvider(url); if (provider == null) { return null; @@ -626,8 +638,9 @@ public abstract class ContentResolver { * @throws FileNotFoundException if the provided URI could not be opened. * @see #openAssetFileDescriptor(Uri, String) */ - public final InputStream openInputStream(Uri uri) + public final @Nullable InputStream openInputStream(@NonNull Uri uri) throws FileNotFoundException { + Preconditions.checkNotNull(uri, "uri"); String scheme = uri.getScheme(); if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { // Note: left here to avoid breaking compatibility. May be removed @@ -658,7 +671,7 @@ public abstract class ContentResolver { * openOutputStream(uri, "w")}. * @throws FileNotFoundException if the provided URI could not be opened. */ - public final OutputStream openOutputStream(Uri uri) + public final @Nullable OutputStream openOutputStream(@NonNull Uri uri) throws FileNotFoundException { return openOutputStream(uri, "w"); } @@ -682,7 +695,7 @@ public abstract class ContentResolver { * @throws FileNotFoundException if the provided URI could not be opened. * @see #openAssetFileDescriptor(Uri, String) */ - public final OutputStream openOutputStream(Uri uri, String mode) + public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); try { @@ -729,8 +742,8 @@ public abstract class ContentResolver { * file exists under the URI or the mode is invalid. * @see #openAssetFileDescriptor(Uri, String) */ - public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode) - throws FileNotFoundException { + public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri, + @NonNull String mode) throws FileNotFoundException { return openFileDescriptor(uri, mode, null); } @@ -774,8 +787,9 @@ public abstract class ContentResolver { * file exists under the URI or the mode is invalid. * @see #openAssetFileDescriptor(Uri, String) */ - public final ParcelFileDescriptor openFileDescriptor(Uri uri, - String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { + public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri, + @NonNull String mode, @Nullable CancellationSignal cancellationSignal) + throws FileNotFoundException { AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal); if (afd == null) { return null; @@ -844,8 +858,8 @@ public abstract class ContentResolver { * @throws FileNotFoundException Throws FileNotFoundException of no * file exists under the URI or the mode is invalid. */ - public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode) - throws FileNotFoundException { + public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mode) throws FileNotFoundException { return openAssetFileDescriptor(uri, mode, null); } @@ -900,8 +914,12 @@ public abstract class ContentResolver { * @throws FileNotFoundException Throws FileNotFoundException of no * file exists under the URI or the mode is invalid. */ - public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, - String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { + public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mode, @Nullable CancellationSignal cancellationSignal) + throws FileNotFoundException { + Preconditions.checkNotNull(uri, "uri"); + Preconditions.checkNotNull(mode, "mode"); + String scheme = uri.getScheme(); if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { if (!"r".equals(mode)) { @@ -1023,8 +1041,8 @@ public abstract class ContentResolver { * @throws FileNotFoundException Throws FileNotFoundException of no * data of the desired type exists under the URI. */ - public final AssetFileDescriptor openTypedAssetFileDescriptor( - Uri uri, String mimeType, Bundle opts) throws FileNotFoundException { + public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException { return openTypedAssetFileDescriptor(uri, mimeType, opts, null); } @@ -1059,9 +1077,12 @@ public abstract class ContentResolver { * @throws FileNotFoundException Throws FileNotFoundException of no * data of the desired type exists under the URI. */ - public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, - String mimeType, Bundle opts, CancellationSignal cancellationSignal) - throws FileNotFoundException { + public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, + @NonNull String mimeType, @Nullable Bundle opts, + @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException { + Preconditions.checkNotNull(uri, "uri"); + Preconditions.checkNotNull(mimeType, "mimeType"); + IContentProvider unstableProvider = acquireUnstableProvider(uri); if (unstableProvider == null) { throw new FileNotFoundException("No content provider: " + uri); @@ -1197,8 +1218,8 @@ public abstract class ContentResolver { * the field. Passing an empty ContentValues will create an empty row. * @return the URL of the newly created row. */ - public final Uri insert(Uri url, ContentValues values) - { + public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) { + Preconditions.checkNotNull(url, "url"); IContentProvider provider = acquireProvider(url); if (provider == null) { throw new IllegalArgumentException("Unknown URL " + url); @@ -1234,9 +1255,11 @@ public abstract class ContentResolver { * @throws RemoteException thrown if a RemoteException is encountered while attempting * to communicate with a remote provider. */ - public ContentProviderResult[] applyBatch(String authority, - ArrayList<ContentProviderOperation> operations) - throws RemoteException, OperationApplicationException { + public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority, + @NonNull ArrayList<ContentProviderOperation> operations) + throws RemoteException, OperationApplicationException { + Preconditions.checkNotNull(authority, "authority"); + Preconditions.checkNotNull(operations, "operations"); ContentProviderClient provider = acquireContentProviderClient(authority); if (provider == null) { throw new IllegalArgumentException("Unknown authority " + authority); @@ -1258,8 +1281,9 @@ public abstract class ContentResolver { * the field. Passing null will create an empty row. * @return the number of newly created rows. */ - public final int bulkInsert(Uri url, ContentValues[] values) - { + public final int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] values) { + Preconditions.checkNotNull(url, "url"); + Preconditions.checkNotNull(values, "values"); IContentProvider provider = acquireProvider(url); if (provider == null) { throw new IllegalArgumentException("Unknown URL " + url); @@ -1289,8 +1313,9 @@ public abstract class ContentResolver { (excluding the WHERE itself). * @return The number of rows deleted. */ - public final int delete(Uri url, String where, String[] selectionArgs) - { + public final int delete(@NonNull Uri url, @Nullable String where, + @Nullable String[] selectionArgs) { + Preconditions.checkNotNull(url, "url"); IContentProvider provider = acquireProvider(url); if (provider == null) { throw new IllegalArgumentException("Unknown URL " + url); @@ -1323,8 +1348,9 @@ public abstract class ContentResolver { * @return the number of rows updated. * @throws NullPointerException if uri or values are null */ - public final int update(Uri uri, ContentValues values, String where, - String[] selectionArgs) { + public final int update(@NonNull Uri uri, @Nullable ContentValues values, + @Nullable String where, @Nullable String[] selectionArgs) { + Preconditions.checkNotNull(uri, "uri"); IContentProvider provider = acquireProvider(uri); if (provider == null) { throw new IllegalArgumentException("Unknown URI " + uri); @@ -1358,14 +1384,10 @@ public abstract class ContentResolver { * @throws NullPointerException if uri or method is null * @throws IllegalArgumentException if uri is not known */ - public final Bundle call( - Uri uri, String method, @Nullable String arg, @Nullable Bundle extras) { - if (uri == null) { - throw new NullPointerException("uri == null"); - } - if (method == null) { - throw new NullPointerException("method == null"); - } + public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method, + @Nullable String arg, @Nullable Bundle extras) { + Preconditions.checkNotNull(uri, "uri"); + Preconditions.checkNotNull(method, "method"); IContentProvider provider = acquireProvider(uri); if (provider == null) { throw new IllegalArgumentException("Unknown URI " + uri); @@ -1467,12 +1489,12 @@ public abstract class ContentResolver { * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} * that services the content at uri or null if there isn't one. */ - public final ContentProviderClient acquireContentProviderClient(Uri uri) { + public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) { + Preconditions.checkNotNull(uri, "uri"); IContentProvider provider = acquireProvider(uri); if (provider != null) { return new ContentProviderClient(this, provider, true); } - return null; } @@ -1487,7 +1509,9 @@ public abstract class ContentResolver { * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} * with the authority of name or null if there isn't one. */ - public final ContentProviderClient acquireContentProviderClient(String name) { + public final @Nullable ContentProviderClient acquireContentProviderClient( + @NonNull String name) { + Preconditions.checkNotNull(name, "name"); IContentProvider provider = acquireProvider(name); if (provider != null) { return new ContentProviderClient(this, provider, true); @@ -1512,7 +1536,9 @@ public abstract class ContentResolver { * can acquire a new one if you would like to try to restart the provider * and perform new operations on it. */ - public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { + public final @Nullable ContentProviderClient acquireUnstableContentProviderClient( + @NonNull Uri uri) { + Preconditions.checkNotNull(uri, "uri"); IContentProvider provider = acquireUnstableProvider(uri); if (provider != null) { return new ContentProviderClient(this, provider, false); @@ -1537,7 +1563,9 @@ public abstract class ContentResolver { * can acquire a new one if you would like to try to restart the provider * and perform new operations on it. */ - public final ContentProviderClient acquireUnstableContentProviderClient(String name) { + public final @Nullable ContentProviderClient acquireUnstableContentProviderClient( + @NonNull String name) { + Preconditions.checkNotNull(name, "name"); IContentProvider provider = acquireUnstableProvider(name); if (provider != null) { return new ContentProviderClient(this, provider, false); @@ -1559,8 +1587,10 @@ public abstract class ContentResolver { * @param observer The object that receives callbacks when changes occur. * @see #unregisterContentObserver */ - public final void registerContentObserver(Uri uri, boolean notifyForDescendents, - ContentObserver observer) { + public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendents, + @NonNull ContentObserver observer) { + Preconditions.checkNotNull(uri, "uri"); + Preconditions.checkNotNull(observer, "observer"); registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); } @@ -1580,7 +1610,8 @@ public abstract class ContentResolver { * @param observer The previously registered observer that is no longer needed. * @see #registerContentObserver */ - public final void unregisterContentObserver(ContentObserver observer) { + public final void unregisterContentObserver(@NonNull ContentObserver observer) { + Preconditions.checkNotNull(observer, "observer"); try { IContentObserver contentObserver = observer.releaseContentObserver(); if (contentObserver != null) { @@ -1603,7 +1634,7 @@ public abstract class ContentResolver { * has requested to receive self-change notifications by implementing * {@link ContentObserver#deliverSelfNotifications()} to return true. */ - public void notifyChange(Uri uri, ContentObserver observer) { + public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) { notifyChange(uri, observer, true /* sync to network */); } @@ -1623,7 +1654,9 @@ public abstract class ContentResolver { * @param syncToNetwork If true, attempt to sync the change to the network. * @see #requestSync(android.accounts.Account, String, android.os.Bundle) */ - public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { + public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer, + boolean syncToNetwork) { + Preconditions.checkNotNull(uri, "uri"); notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId()); } @@ -1653,7 +1686,9 @@ public abstract class ContentResolver { * * @see #getPersistedUriPermissions() */ - public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { + public void takePersistableUriPermission(@NonNull Uri uri, + @Intent.AccessUriMode int modeFlags) { + Preconditions.checkNotNull(uri, "uri"); try { ActivityManagerNative.getDefault().takePersistableUriPermission( ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); @@ -1669,7 +1704,9 @@ public abstract class ContentResolver { * * @see #getPersistedUriPermissions() */ - public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { + public void releasePersistableUriPermission(@NonNull Uri uri, + @Intent.AccessUriMode int modeFlags) { + Preconditions.checkNotNull(uri, "uri"); try { ActivityManagerNative.getDefault().releasePersistableUriPermission( ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); @@ -1686,7 +1723,7 @@ public abstract class ContentResolver { * @see #takePersistableUriPermission(Uri, int) * @see #releasePersistableUriPermission(Uri, int) */ - public List<UriPermission> getPersistedUriPermissions() { + public @NonNull List<UriPermission> getPersistedUriPermissions() { try { return ActivityManagerNative.getDefault() .getPersistedUriPermissions(mPackageName, true).getList(); @@ -1701,7 +1738,7 @@ public abstract class ContentResolver { * <em>from</em> the calling app. Only grants taken with * {@link #takePersistableUriPermission(Uri, int)} are returned. */ - public List<UriPermission> getOutgoingPersistedUriPermissions() { + public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() { try { return ActivityManagerNative.getDefault() .getPersistedUriPermissions(mPackageName, false).getList(); diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 33c0b87..08c5236 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -254,12 +254,14 @@ public class IntentFilter implements Parcelable { * HTTP scheme. * * @see #addDataScheme(String) + * @hide */ public static final String SCHEME_HTTP = "http"; /** * HTTPS scheme. * * @see #addDataScheme(String) + * @hide */ public static final String SCHEME_HTTPS = "https"; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 83b0140..c92c256 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -36,6 +36,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.Bundle; +import android.os.FileUtils; import android.os.PatternMatcher; import android.os.UserHandle; import android.text.TextUtils; @@ -1194,7 +1195,8 @@ public class PackageParser { } } - private static String validateName(String name, boolean requiresSeparator) { + private static String validateName(String name, boolean requireSeparator, + boolean requireFilename) { final int N = name.length(); boolean hasSep = false; boolean front = true; @@ -1216,7 +1218,10 @@ public class PackageParser { } return "bad character '" + c + "'"; } - return hasSep || !requiresSeparator + if (requireFilename && !FileUtils.isValidExtFilename(name)) { + return "Invalid filename"; + } + return hasSep || !requireSeparator ? null : "must have at least one '.' separator"; } @@ -1240,7 +1245,7 @@ public class PackageParser { final String packageName = attrs.getAttributeValue(null, "package"); if (!"android".equals(packageName)) { - final String error = validateName(packageName, true); + final String error = validateName(packageName, true, true); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest package: " + error); @@ -1252,7 +1257,7 @@ public class PackageParser { if (splitName.length() == 0) { splitName = null; } else { - final String error = validateName(splitName, false); + final String error = validateName(splitName, false, false); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest split: " + error); @@ -1391,7 +1396,7 @@ public class PackageParser { String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { - String nameError = validateName(str, true); + String nameError = validateName(str, true, false); if (nameError != null && !"android".equals(pkgName)) { outError[0] = "<manifest> specifies bad sharedUserId name \"" + str + "\": " + nameError; @@ -1973,7 +1978,7 @@ public class PackageParser { return null; } String subName = proc.substring(1); - String nameError = validateName(subName, false); + String nameError = validateName(subName, false, false); if (nameError != null) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; @@ -1981,7 +1986,7 @@ public class PackageParser { } return (pkg + proc).intern(); } - String nameError = validateName(proc, true); + String nameError = validateName(proc, true, false); if (nameError != null && !"system".equals(proc)) { outError[0] = "Invalid " + type + " name " + proc + " in package " + pkg + ": " + nameError; diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index ed167f0..8512b23 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -79,7 +80,7 @@ public class CameraDeviceImpl extends CameraDevice { private volatile StateCallbackKK mSessionStateCallback; private final Handler mDeviceHandler; - private volatile boolean mClosing = false; + private final AtomicBoolean mClosing = new AtomicBoolean(); private boolean mInError = false; private boolean mIdle = true; @@ -906,6 +907,10 @@ public class CameraDeviceImpl extends CameraDevice { @Override public void close() { synchronized (mInterfaceLock) { + if (mClosing.getAndSet(true)) { + return; + } + try { if (mRemoteDevice != null) { mRemoteDevice.disconnect(); @@ -1917,7 +1922,7 @@ public class CameraDeviceImpl extends CameraDevice { /** Whether the camera device has started to close (may not yet have finished) */ private boolean isClosed() { - return mClosing; + return mClosing.get(); } private CameraCharacteristics getCharacteristics() { diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index a3a998e..2fb3203 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -85,7 +85,10 @@ public class LegacyCameraDevice implements AutoCloseable { private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200; private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000; - public static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding + public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding + + // Keep up to date with values in system/core/include/system/window.h + public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1; private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) { if (holder == null) { @@ -690,6 +693,13 @@ public class LegacyCameraDevice implements AutoCloseable { LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp)); } + static void setScalingMode(Surface surface, int mode) + throws BufferQueueAbandonedException { + checkNotNull(surface); + LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode)); + } + + private static native int nativeDetectSurfaceType(Surface surface); private static native int nativeDetectSurfaceDimens(Surface surface, @@ -717,5 +727,7 @@ public class LegacyCameraDevice implements AutoCloseable { private static native int nativeDetectSurfaceUsageFlags(Surface surface); + private static native int nativeSetScalingMode(Surface surface, int scalingMode); + static native int nativeGetJpegFooterSize(); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java index 33a802b..8bdd42a 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -415,8 +415,9 @@ public class LegacyMetadataMapper { Range<Integer>[] ranges = new Range[rangesSize]; int i = 0; for (int[] r : fpsRanges) { - ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], - r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + ranges[i++] = Range.create( + (int) Math.floor(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0), + (int) Math.ceil(r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0)); } m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java index d5d7f0d..6a44ac5 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java @@ -162,17 +162,19 @@ public class LegacyRequestMapper { if (aeFpsRange != null) { int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange); - // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range? - boolean supported = false; + int[] rangeToApply = null; for(int[] range : params.getSupportedPreviewFpsRange()) { - if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) { - supported = true; + // Round range up/down to integer FPS value + int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000; + int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000; + if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) { + rangeToApply = range; break; } } - if (supported) { - params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], - legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + if (rangeToApply != null) { + params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], + rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); } else { Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); } @@ -626,8 +628,8 @@ public class LegacyRequestMapper { private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) { int[] legacyFps = new int[2]; - legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower(); - legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper(); + legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000; + legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000; return legacyFps; } diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 5ea1ab8..4866598 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -187,8 +187,18 @@ public class RequestThreadManager { private final Camera.ErrorCallback mErrorCallback = new Camera.ErrorCallback() { @Override public void onError(int i, Camera camera) { - Log.e(TAG, "Received error " + i + " from the Camera1 ErrorCallback"); - mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); + switch(i) { + case Camera.CAMERA_ERROR_EVICTED: { + flush(); + mDeviceState.setError( + CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED); + } break; + default: { + Log.e(TAG, "Received error " + i + " from the Camera1 ErrorCallback"); + mDeviceState.setError( + CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); + } break; + } } }; @@ -384,6 +394,8 @@ public class RequestThreadManager { callbackOutputSizes.add(outSize); break; default: + LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice. + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); mPreviewOutputs.add(s); previewOutputSizes.add(outSize); break; @@ -412,6 +424,9 @@ public class RequestThreadManager { mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs, + callbackOutputSizes, mParams); + if (previewOutputSizes.size() > 0) { Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes); @@ -419,6 +434,9 @@ public class RequestThreadManager { // Find largest jpeg dimension - assume to have the same aspect ratio as sensor. Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams); + Size chosenJpegDimen = (smallestSupportedJpegSize != null) ? smallestSupportedJpegSize + : largestJpegDimen; + List<Size> supportedPreviewSizes = ParameterUtils.convertSizeList( mParams.getSupportedPreviewSizes()); @@ -430,7 +448,7 @@ public class RequestThreadManager { for (Size s : supportedPreviewSizes) { long currArea = s.getWidth() * s.getHeight(); long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight(); - if (checkAspectRatiosMatch(largestJpegDimen, s) && (currArea < bestArea && + if (checkAspectRatiosMatch(chosenJpegDimen, s) && (currArea < bestArea && currArea >= largestOutputArea)) { bestPreviewDimen = s; } @@ -451,8 +469,6 @@ public class RequestThreadManager { } } - Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs, - callbackOutputSizes, mParams); if (smallestSupportedJpegSize != null) { /* * Set takePicture size to the smallest supported JPEG size large enough diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 45f1889..a5490ef 100644 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -400,16 +400,27 @@ public class Keyboard { public void onPressed() { pressed = !pressed; } - + /** - * Changes the pressed state of the key. If it is a sticky key, it will also change the - * toggled state of the key if the finger was release inside. - * @param inside whether the finger was released inside the key + * Changes the pressed state of the key. + * + * <p>Toggled state of the key will be flipped when all the following conditions are + * fulfilled:</p> + * + * <ul> + * <li>This is a sticky key, that is, {@link #sticky} is {@code true}. + * <li>The parameter {@code inside} is {@code true}. + * <li>{@link android.os.Build.VERSION#SDK_INT} is greater than + * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}. + * </ul> + * + * @param inside whether the finger was released inside the key. Works only on Android M and + * later. See the method document for details. * @see #onPressed() */ public void onReleased(boolean inside) { pressed = !pressed; - if (sticky) { + if (sticky && inside) { on = !on; } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index a6efc58..d165240 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1177,8 +1177,13 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_ALARM = 0x000e; // Record that we have decided we need to collect new stats data. public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f; + // Event for a package becoming inactive due to being unused for a period of time. + public static final int EVENT_PACKAGE_INACTIVE = 0x0010; + // Event for a package becoming active due to an interaction. + public static final int EVENT_PACKAGE_ACTIVE = 0x0011; + // Number of event types. - public static final int EVENT_COUNT = 0x0010; + public static final int EVENT_COUNT = 0x0012; // Mask to extract out only the type part of the event. public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); @@ -1835,12 +1840,12 @@ public abstract class BatteryStats implements Parcelable { public static final String[] HISTORY_EVENT_NAMES = new String[] { "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn", - "motion", "active", "pkginst", "pkgunin", "alarm", "stats" + "motion", "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active" }; public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn", - "Esm", "Eac", "Epi", "Epu", "Eal", "Est" + "Esm", "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa" }; /** @@ -3536,8 +3541,15 @@ public abstract class BatteryStats implements Parcelable { } printmAh(pw, bs.totalPowerMah); - if (bs.drainType == BatterySipper.DrainType.APP) { + if (bs.usagePowerMah != bs.totalPowerMah) { + // If the usage (generic power) isn't the whole amount, we list out + // what components are involved in the calculation. + pw.print(" ("); + if (bs.usagePowerMah != 0) { + pw.print(" usage="); + printmAh(pw, bs.usagePowerMah); + } if (bs.cpuPowerMah != 0) { pw.print(" cpu="); printmAh(pw, bs.cpuPowerMah); diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 917271d..864225a 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -24,6 +24,8 @@ import android.util.Log; import android.util.Slog; import android.webkit.MimeTypeMap; +import com.android.internal.annotations.VisibleForTesting; + import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -34,6 +36,7 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; @@ -456,6 +459,7 @@ public class FileUtils { res.append('_'); } } + trimFilename(res, 255); return res.toString(); } @@ -504,9 +508,31 @@ public class FileUtils { res.append('_'); } } + // Even though vfat allows 255 UCS-2 chars, we might eventually write to + // ext4 through a FUSE layer, so use that limit. + trimFilename(res, 255); + return res.toString(); + } + + @VisibleForTesting + public static String trimFilename(String str, int maxBytes) { + final StringBuilder res = new StringBuilder(str); + trimFilename(res, maxBytes); return res.toString(); } + private static void trimFilename(StringBuilder res, int maxBytes) { + byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8); + if (raw.length > maxBytes) { + maxBytes -= 3; + while (raw.length > maxBytes) { + res.deleteCharAt(res.length() / 2); + raw = res.toString().getBytes(StandardCharsets.UTF_8); + } + res.insert(res.length() / 2, "..."); + } + } + public static String rewriteAfterRename(File beforeDir, File afterDir, String path) { if (path == null) return null; final File result = rewriteAfterRename(beforeDir, afterDir, new File(path)); diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 1c9c713..135f369 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -621,6 +621,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { final int fd = getFd(); Parcel.clearFileDescriptor(mFd); writeCommStatusAndClose(Status.DETACHED, null); + mClosed = true; + mGuard.close(); + releaseResources(); return fd; } } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 8b18f32..7a1aa1e 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -878,7 +878,10 @@ public final class PowerManager { * off network access to apps. You can monitor for changes to this state with * {@link #ACTION_DEVICE_IDLE_MODE_CHANGED}. * - * @return Returns true if currently in low power mode, else false. + * @return Returns true if currently in active device idle mode, else false. This is + * when idle mode restrictions are being actively applied; it will return false if the + * device is in a long-term idle mode but currently running a maintenance window where + * restrictions have been lifted. */ public boolean isDeviceIdleMode() { try { diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java index 04e54aa..397d87e 100644 --- a/core/java/android/os/storage/DiskInfo.java +++ b/core/java/android/os/storage/DiskInfo.java @@ -40,6 +40,8 @@ public class DiskInfo implements Parcelable { "android.os.storage.action.DISK_SCANNED"; public static final String EXTRA_DISK_ID = "android.os.storage.extra.DISK_ID"; + public static final String EXTRA_VOLUME_COUNT = + "android.os.storage.extra.VOLUME_COUNT"; public static final int FLAG_ADOPTABLE = 1 << 0; public static final int FLAG_DEFAULT_PRIMARY = 1 << 1; @@ -80,6 +82,12 @@ public class DiskInfo implements Parcelable { if (label.toLowerCase().contains("generic")) { return false; } + if (label.toLowerCase().startsWith("usb")) { + return false; + } + if (label.toLowerCase().startsWith("multiple")) { + return false; + } return true; } diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java index c958fb0..cade9d7 100644 --- a/core/java/android/os/storage/IMountServiceListener.java +++ b/core/java/android/os/storage/IMountServiceListener.java @@ -113,6 +113,13 @@ public interface IMountServiceListener extends IInterface { reply.writeNoException(); return true; } + case TRANSACTION_onDiskDestroyed: { + data.enforceInterface(DESCRIPTOR); + final DiskInfo disk = (DiskInfo) data.readParcelable(null); + onDiskDestroyed(disk); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); } @@ -246,6 +253,22 @@ public interface IMountServiceListener extends IInterface { _data.recycle(); } } + + @Override + public void onDiskDestroyed(DiskInfo disk) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeParcelable(disk, 0); + mRemote.transact(Stub.TRANSACTION_onDiskDestroyed, _data, _reply, + android.os.IBinder.FLAG_ONEWAY); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } } static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0); @@ -254,6 +277,7 @@ public interface IMountServiceListener extends IInterface { static final int TRANSACTION_onVolumeRecordChanged = (IBinder.FIRST_CALL_TRANSACTION + 3); static final int TRANSACTION_onVolumeForgotten = (IBinder.FIRST_CALL_TRANSACTION + 4); static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 5); + static final int TRANSACTION_onDiskDestroyed = (IBinder.FIRST_CALL_TRANSACTION + 6); } /** @@ -280,4 +304,6 @@ public interface IMountServiceListener extends IInterface { public void onVolumeForgotten(String fsUuid) throws RemoteException; public void onDiskScanned(DiskInfo disk, int volumeCount) throws RemoteException; + + public void onDiskDestroyed(DiskInfo disk) throws RemoteException; } diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java index 214c60d..4cf83fd 100644 --- a/core/java/android/os/storage/StorageEventListener.java +++ b/core/java/android/os/storage/StorageEventListener.java @@ -49,4 +49,7 @@ public class StorageEventListener { public void onDiskScanned(DiskInfo disk, int volumeCount) { } + + public void onDiskDestroyed(DiskInfo disk) { + } } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 4bbaaa1..9b26f24 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -101,6 +101,7 @@ public class StorageManager { private static final int MSG_VOLUME_RECORD_CHANGED = 3; private static final int MSG_VOLUME_FORGOTTEN = 4; private static final int MSG_DISK_SCANNED = 5; + private static final int MSG_DISK_DESTROYED = 6; final StorageEventListener mCallback; final Handler mHandler; @@ -135,6 +136,10 @@ public class StorageManager { mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2); args.recycle(); return true; + case MSG_DISK_DESTROYED: + mCallback.onDiskDestroyed((DiskInfo) args.arg1); + args.recycle(); + return true; } args.recycle(); return false; @@ -184,6 +189,13 @@ public class StorageManager { args.argi2 = volumeCount; mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget(); } + + @Override + public void onDiskDestroyed(DiskInfo disk) throws RemoteException { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = disk; + mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget(); + } } /** diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 372725f..8d11527 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -55,6 +55,8 @@ public class VolumeInfo implements Parcelable { "android.os.storage.action.VOLUME_STATE_CHANGED"; public static final String EXTRA_VOLUME_ID = "android.os.storage.extra.VOLUME_ID"; + public static final String EXTRA_VOLUME_STATE = + "android.os.storage.extra.VOLUME_STATE"; /** Stub volume representing internal private storage */ public static final String ID_PRIVATE_INTERNAL = "private"; diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index d9c412b..aebe7f1 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -8931,157 +8931,4 @@ public final class ContactsContract { public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET"; } } - - /** - * @hide - */ - protected interface MetadataSyncColumns { - - /** - * The raw contact backup id. - * A reference to the {@link ContactsContract.RawContacts#BACKUP_ID} that save the - * persistent unique id for each raw contact within its source system. - * - * @hide - */ - public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id"; - - /** - * The account type to which the raw_contact of this item is associated. See - * {@link RawContacts#ACCOUNT_TYPE} - * - * @hide - */ - public static final String ACCOUNT_TYPE = "account_type"; - - /** - * The account name to which the raw_contact of this item is associated. See - * {@link RawContacts#ACCOUNT_NAME} - * - * @hide - */ - public static final String ACCOUNT_NAME = "account_name"; - - /** - * The data set within the account that the raw_contact of this row belongs to. This allows - * multiple sync adapters for the same account type to distinguish between - * each others' data. - * {@link RawContacts#DATA_SET} - * - * @hide - */ - public static final String DATA_SET = "data_set"; - - /** - * A text column contains the Json string got from People API. The Json string contains - * all the metadata related to the raw contact, i.e., all the data fields and - * aggregation exceptions. - * - * Here is an example of the Json string got from the actual schema. - * <pre> - * { - * "unique_contact_id": { - * "account_type": "CUSTOM_ACCOUNT", - * "custom_account_type": "facebook", - * "account_name": "android-test", - * "contact_id": "1111111", - * "data_set": "FOCUS" - * }, - * "contact_prefs": { - * "send_to_voicemail": true, - * "starred": false, - * "pinned": 2 - * }, - * "aggregation_data": [ - * { - * "type": "TOGETHER", - * "contact_ids": [ - * { - * "account_type": "GOOGLE_ACCOUNT", - * "account_name": "android-test2", - * "contact_id": "2222222", - * "data_set": "GOOGLE_PLUS" - * }, - * { - * "account_type": "GOOGLE_ACCOUNT", - * "account_name": "android-test3", - * "contact_id": "3333333", - * "data_set": "CUSTOM", - * "custom_data_set": "custom type" - * } - * ] - * } - * ], - * "field_data": [ - * { - * "field_data_id": "1001", - * "field_data_prefs": { - * "is_primary": true, - * "is_super_primary": true - * }, - * "usage_stats": [ - * { - * "usage_type": "CALL", - * "last_time_used": 10000001, - * "usage_count": 10 - * } - * ] - * } - * ] - * } - * </pre> - * - * @hide - */ - public static final String DATA = "data"; - - /** - * The "deleted" flag: "0" by default, "1" if the row has been marked - * for deletion. When {@link android.content.ContentResolver#delete} is - * called on a raw contact, updating MetadataSync table to set the flag of the raw contact - * as "1", then metadata sync adapter deletes the raw contact metadata on the server. - * <P>Type: INTEGER</P> - * - * @hide - */ - public static final String DELETED = "deleted"; - } - - /** - * Constants for the metadata sync table. This table is used to cache the metadata_sync data - * from server before it is merged into other CP2 tables. - * - * @hide - */ - public static final class MetadataSync implements BaseColumns, MetadataSyncColumns { - - /** The authority for the contacts metadata */ - public static final String METADATA_AUTHORITY = "com.android.contacts.metadata"; - - /** A content:// style uri to the authority for the contacts metadata */ - public static final Uri METADATA_AUTHORITY_URI = Uri.parse( - "content://" + METADATA_AUTHORITY); - - /** - * This utility class cannot be instantiated - */ - private MetadataSync() { - } - - /** - * The content:// style URI for this table. - */ - public static final Uri CONTENT_URI = Uri.withAppendedPath(METADATA_AUTHORITY_URI, - "metadata_sync"); - - /** - * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata"; - - /** - * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata. - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata"; - } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 167d8e5..e335f6d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5551,13 +5551,6 @@ public final class Settings { public static final String SLEEP_TIMEOUT = "sleep_timeout"; /** - * Duration in milliseconds that an app should be inactive before it is considered idle. - * <p/>Type: Long - * @hide - */ - public static final String APP_IDLE_DURATION = "app_idle_duration"; - - /** * Controls whether double tap to wake is enabled. * @hide */ @@ -7087,6 +7080,58 @@ public final class Settings { BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_"; /** + * Device Idle (Doze) specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "inactive_timeout=60000,sensing_timeout=400000" + * + * The following keys are supported: + * + * <pre> + * inactive_to (long) + * sensing_to (long) + * motion_inactive_to (long) + * idle_after_inactive_to (long) + * idle_pending_to (long) + * max_idle_pending_to (long) + * idle_pending_factor (float) + * idle_to (long) + * max_idle_to (long) + * idle_factor (float) + * min_time_to_alarm (long) + * max_temp_app_whitelist_duration (long) + * </pre> + * + * <p> + * Type: string + * @hide + * @see com.android.server.DeviceIdleController.Constants + */ + public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants"; + + /** + * App standby (app idle) specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "idle_duration=5000,parole_interval=4500" + * + * The following keys are supported: + * + * <pre> + * idle_duration (long) + * wallclock_threshold (long) + * parole_interval (long) + * parole_duration (long) + * </pre> + * + * <p> + * Type: string + * @hide + * @see com.android.server.usage.UsageStatsService.SettingsObserver + */ + public static final String APP_IDLE_CONSTANTS = "app_idle_constants"; + + /** * Get the key that retrieves a bluetooth headset's priority. * @hide */ diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java index 9eb22ef..890ea3d 100644 --- a/core/java/android/speech/tts/UtteranceProgressListener.java +++ b/core/java/android/speech/tts/UtteranceProgressListener.java @@ -61,16 +61,16 @@ public abstract class UtteranceProgressListener { /** * Called when an utterance has been stopped while in progress or flushed from the - * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()} - * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in + * synthesis queue. This can happen if a client calls {@link TextToSpeech#stop()} + * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods. * * @param utteranceId the utterance ID of the utterance. - * @param isStarted If true, then utterance was interrupted while being synthesized - * and it's output is incomplete. If it's false, then utterance was flushed + * @param interrupted If true, then the utterance was interrupted while being synthesized + * and its output is incomplete. If false, then the utterance was flushed * before the synthesis started. */ - public void onStop(String utteranceId, boolean isStarted) { + public void onStop(String utteranceId, boolean interrupted) { } /** @@ -99,7 +99,7 @@ public abstract class UtteranceProgressListener { } @Override - public void onStop(String utteranceId, boolean isStarted) { + public void onStop(String utteranceId, boolean interrupted) { listener.onUtteranceCompleted(utteranceId); } }; diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 6c4d8fd..d51aa79 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -1790,6 +1790,15 @@ public class TextUtils { } } + /** + * Return localized string representing the given number of selected items. + * + * @hide + */ + public static CharSequence formatSelectedCount(int count) { + return Resources.getSystem().getQuantityString(R.plurals.selected_count, count, count); + } + private static Object sLock = new Object(); private static char[] sTemp = null; diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index 6ed3885..4ee9807 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -266,7 +266,7 @@ public final class ArrayMap<K, V> implements Map<K, V> { /** * Create a new ArrayMap with the mappings from the given ArrayMap. */ - public ArrayMap(ArrayMap map) { + public ArrayMap(ArrayMap<K, V> map) { this(); if (map != null) { putAll(map); @@ -843,7 +843,8 @@ public final class ArrayMap<K, V> implements Map<K, V> { * in the array map. * * <p><b>Note:</b> this is a very inefficient way to access the array contents, it - * requires generating a number of temporary objects.</p> + * requires generating a number of temporary objects and allocates additional state + * information associated with the container that will remain for the life of the container.</p> * * <p><b>Note:</b></p> the semantics of this * Set are subtly different than that of a {@link java.util.HashMap}: most important, @@ -861,7 +862,8 @@ public final class ArrayMap<K, V> implements Map<K, V> { * in the array map. * * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it - * requires generating a number of temporary objects.</p> + * requires generating a number of temporary objects and allocates additional state + * information associated with the container that will remain for the life of the container.</p> */ @Override public Set<K> keySet() { @@ -873,7 +875,8 @@ public final class ArrayMap<K, V> implements Map<K, V> { * in the array map. * * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it - * requires generating a number of temporary objects.</p> + * requires generating a number of temporary objects and allocates additional state + * information associated with the container that will remain for the life of the container.</p> */ @Override public Collection<V> values() { diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index 7da3941..b7a3c42 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -42,8 +42,6 @@ import java.util.Set; * you have no control over this shrinking -- if you set a capacity and then remove an * item, it may reduce the capacity to better match the current size. In the future an * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p> - * - * @hide */ public final class ArraySet<E> implements Collection<E>, Set<E> { private static final boolean DEBUG = false; @@ -660,11 +658,24 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return mCollections; } + /** + * Return an {@link java.util.Iterator} over all values in the set. + * + * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it + * requires generating a number of temporary objects and allocates additional state + * information associated with the container that will remain for the life of the container.</p> + */ @Override public Iterator<E> iterator() { return getCollection().getKeySet().iterator(); } + /** + * Determine if the array set contains all of the values in the given collection. + * @param collection The collection whose contents are to be checked against. + * @return Returns true if this array set contains a value for every entry + * in <var>collection</var>, else returns false. + */ @Override public boolean containsAll(Collection<?> collection) { Iterator<?> it = collection.iterator(); @@ -676,6 +687,10 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return true; } + /** + * Perform an {@link #add(Object)} of all values in <var>collection</var> + * @param collection The collection whose contents are to be retrieved. + */ @Override public boolean addAll(Collection<? extends E> collection) { ensureCapacity(mSize + collection.size()); @@ -686,6 +701,11 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return added; } + /** + * Remove all values in the array set that exist in the given collection. + * @param collection The collection whose contents are to be used to remove values. + * @return Returns true if any values were removed from the array set, else false. + */ @Override public boolean removeAll(Collection<?> collection) { boolean removed = false; @@ -695,6 +715,12 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return removed; } + /** + * Remove all values in the array set that do <b>not</b> exist in the given collection. + * @param collection The collection whose contents are to be used to determine which + * values to keep. + * @return Returns true if any values were removed from the array set, else false. + */ @Override public boolean retainAll(Collection<?> collection) { boolean removed = false; diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java new file mode 100644 index 0000000..4abdde0 --- /dev/null +++ b/core/java/android/util/KeyValueListParser.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.util; + +import android.text.TextUtils; + +/** + * Parses a list of key=value pairs, separated by some delimiter, and puts the results in + * an internal Map. Values can be then queried by key, or if not found, a default value + * can be used. + * @hide + */ +public class KeyValueListParser { + private final ArrayMap<String, String> mValues = new ArrayMap<>(); + private final TextUtils.StringSplitter mSplitter; + + /** + * Constructs a new KeyValueListParser. This can be reused for different strings + * by calling {@link #setString(String)}. + * @param delim The delimiter that separates key=value pairs. + */ + public KeyValueListParser(char delim) { + mSplitter = new TextUtils.SimpleStringSplitter(delim); + } + + /** + * Resets the parser with a new string to parse. The string is expected to be in the following + * format: + * <pre>key1=value,key2=value,key3=value</pre> + * + * where the delimiter is a comma. + * + * @param str the string to parse. + * @throws IllegalArgumentException if the string is malformed. + */ + public void setString(String str) throws IllegalArgumentException { + mValues.clear(); + if (str != null) { + mSplitter.setString(str); + for (String pair : mSplitter) { + int sep = pair.indexOf('='); + if (sep < 0) { + mValues.clear(); + throw new IllegalArgumentException( + "'" + pair + "' in '" + str + "' is not a valid key-value pair"); + } + mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim()); + } + } + } + + /** + * Get the value for key as a long. + * @param key The key to lookup. + * @param def The value to return if the key was not found, or the value was not a long. + * @return the long value associated with the key. + */ + public long getLong(String key, long def) { + String value = mValues.get(key); + if (value != null) { + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + // fallthrough + } + } + return def; + } + + /** + * Get the value for key as a float. + * @param key The key to lookup. + * @param def The value to return if the key was not found, or the value was not a float. + * @return the float value associated with the key. + */ + public float getFloat(String key, float def) { + String value = mValues.get(key); + if (value != null) { + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + // fallthrough + } + } + return def; + } + + /** + * Get the value for key as a string. + * @param key The key to lookup. + * @param def The value to return if the key was not found. + * @return the string value associated with the key. + */ + public String getString(String key, String def) { + String value = mValues.get(key); + if (value != null) { + return value; + } + return def; + } +} diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index f7d2821..353388d 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -246,41 +246,65 @@ public class TimeUtils { public static final long NANOS_PER_MS = 1000000; private static final Object sFormatSync = new Object(); - private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5]; - - private static final long LARGEST_DURATION = (1000 * DateUtils.DAY_IN_MILLIS) - 1; + private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10]; + private static char[] sTmpFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10]; static private int accumField(int amt, int suffix, boolean always, int zeropad) { - if (amt > 99 || (always && zeropad >= 3)) { - return 3+suffix; - } - if (amt > 9 || (always && zeropad >= 2)) { - return 2+suffix; - } - if (always || amt > 0) { - return 1+suffix; + if (amt > 999) { + int num = 0; + while (amt != 0) { + num++; + amt /= 10; + } + return num + suffix; + } else { + if (amt > 99 || (always && zeropad >= 3)) { + return 3+suffix; + } + if (amt > 9 || (always && zeropad >= 2)) { + return 2+suffix; + } + if (always || amt > 0) { + return 1+suffix; + } } return 0; } - static private int printField(char[] formatStr, int amt, char suffix, int pos, + static private int printFieldLocked(char[] formatStr, int amt, char suffix, int pos, boolean always, int zeropad) { if (always || amt > 0) { final int startPos = pos; - if ((always && zeropad >= 3) || amt > 99) { - int dig = amt/100; - formatStr[pos] = (char)(dig + '0'); - pos++; - amt -= (dig*100); - } - if ((always && zeropad >= 2) || amt > 9 || startPos != pos) { - int dig = amt/10; - formatStr[pos] = (char)(dig + '0'); + if (amt > 999) { + int tmp = 0; + while (amt != 0 && tmp < sTmpFormatStr.length) { + int dig = amt % 10; + sTmpFormatStr[tmp] = (char)(dig + '0'); + tmp++; + amt /= 10; + } + tmp--; + while (tmp >= 0) { + formatStr[pos] = sTmpFormatStr[tmp]; + pos++; + tmp--; + } + } else { + if ((always && zeropad >= 3) || amt > 99) { + int dig = amt/100; + formatStr[pos] = (char)(dig + '0'); + pos++; + amt -= (dig*100); + } + if ((always && zeropad >= 2) || amt > 9 || startPos != pos) { + int dig = amt/10; + formatStr[pos] = (char)(dig + '0'); + pos++; + amt -= (dig*10); + } + formatStr[pos] = (char)(amt + '0'); pos++; - amt -= (dig*10); } - formatStr[pos] = (char)(amt + '0'); - pos++; formatStr[pos] = suffix; pos++; } @@ -312,10 +336,6 @@ public class TimeUtils { duration = -duration; } - if (duration > LARGEST_DURATION) { - duration = LARGEST_DURATION; - } - int millis = (int)(duration%1000); int seconds = (int) Math.floor(duration / 1000); int days = 0, hours = 0, minutes = 0; @@ -353,11 +373,11 @@ public class TimeUtils { int start = pos; boolean zeropad = fieldLen != 0; - pos = printField(formatStr, days, 'd', pos, false, 0); - pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0); + pos = printFieldLocked(formatStr, days, 'd', pos, false, 0); + pos = printFieldLocked(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0); + pos = printFieldLocked(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0); + pos = printFieldLocked(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0); + pos = printFieldLocked(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0); formatStr[pos] = 's'; return pos + 1; } diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index d2b6533..a865307 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -22,6 +22,7 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.util.Log; import android.util.TimeUtils; @@ -160,6 +161,14 @@ public final class Choreographer { FrameInfo mFrameInfo = new FrameInfo(); /** + * Must be kept in sync with CALLBACK_* ints below, used to index into this array. + * @hide + */ + private static final String[] CALLBACK_TRACE_TITLES = { + "input", "animation", "traversal", "commit" + }; + + /** * Callback type: Input callback. Runs first. * @hide */ @@ -584,16 +593,22 @@ public final class Choreographer { mLastFrameTimeNanos = frameTimeNanos; } - mFrameInfo.markInputHandlingStart(); - doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); + try { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame"); + + mFrameInfo.markInputHandlingStart(); + doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); - mFrameInfo.markAnimationsStart(); - doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); + mFrameInfo.markAnimationsStart(); + doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); - mFrameInfo.markPerformTraversalsStart(); - doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); + mFrameInfo.markPerformTraversalsStart(); + doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); - doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); + doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } if (DEBUG_FRAMES) { final long endNanos = System.nanoTime(); @@ -627,6 +642,7 @@ public final class Choreographer { // safe by ensuring the commit time is always at least one frame behind. if (callbackType == Choreographer.CALLBACK_COMMIT) { final long jitterNanos = now - frameTimeNanos; + Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos); if (jitterNanos >= 2 * mFrameIntervalNanos) { final long lastFrameOffset = jitterNanos % mFrameIntervalNanos + mFrameIntervalNanos; @@ -644,6 +660,7 @@ public final class Choreographer { } } try { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]); for (CallbackRecord c = callbacks; c != null; c = c.next) { if (DEBUG_FRAMES) { Log.d(TAG, "RunCallback: type=" + callbackType @@ -661,6 +678,7 @@ public final class Choreographer { callbacks = next; } while (callbacks != null); } + Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index be372d0..0df8ea9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -741,6 +741,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static boolean sUseBrokenMakeMeasureSpec = false; /** + * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED + */ + static boolean sUseZeroUnspecifiedMeasureSpec = false; + + /** * Ignore any optimizations using the measure cache. */ private static boolean sIgnoreMeasureCache = false; @@ -3796,6 +3801,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Canvas.sCompatibilityRestore = targetSdkVersion < MNC; + // In MNC and newer, our widgets can pass a "hint" value in the size + // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers + // know what the expected parent size is going to be, so e.g. list items can size + // themselves at 1/3 the size of their container. It breaks older apps though, + // specifically apps that use some popular open source libraries. + sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < MNC; + sCompatibilityDone = true; } } @@ -17163,21 +17175,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * If the view has a ColorDrawable background, returns the color of that - * drawable. - * - * @return The color of the ColorDrawable background, if set, otherwise 0. - * @hide - */ - @ColorInt - public int getBackgroundColor() { - if (mBackground instanceof ColorDrawable) { - return ((ColorDrawable) mBackground).getColor(); - } - return 0; - } - - /** * Set the background to a given resource. The resource should refer to * a Drawable object or 0 to remove the background. * @param resid The identifier of the resource. @@ -21032,6 +21029,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED + * will automatically get a size of 0. Older apps expect this. + * + * @hide internal use only for compatibility with system widgets and older apps + */ + public static int makeSafeMeasureSpec(int size, int mode) { + if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { + return 0; + } + return makeMeasureSpec(size, mode); + } + + /** * Extracts the mode from the supplied measure specification. * * @param measureSpec the measure specification to extract the mode from diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index dd32f85..89743e5 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5963,12 +5963,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be - resultSize = size; + resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be - resultSize = size; + resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e1e0154..8b57d96 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -663,6 +663,10 @@ public final class ViewRootImpl implements ViewParent, return mWindowAttributes.flags; } + public int getDisplayId() { + return mDisplay.getDisplayId(); + } + public CharSequence getTitle() { return mWindowAttributes.getTitle(); } @@ -1105,12 +1109,7 @@ public final class ViewRootImpl implements ViewParent, Debug.startMethodTracing("ViewAncestor"); } - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals"); - try { - performTraversals(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } + performTraversals(); if (mProfile) { Debug.stopMethodTracing(); diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 8ceb166..d06cd83 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -201,6 +201,17 @@ public abstract class ViewStructure { public abstract void setChildCount(int num); /** + * Add to this view's child count. This increases the current child count by + * <var>num</var> children beyond what was last set by {@link #setChildCount} + * or {@link #addChildCount}. The index at which the new child starts in the child + * array is returned. + * + * @param num The number of new children to add. + * @return Returns the index in the child array at which the new children start. + */ + public abstract int addChildCount(int num); + + /** * Return the child count as set by {@link #setChildCount}. */ public abstract int getChildCount(); diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index b7d529e..b4ef58a 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -333,8 +333,8 @@ public final class WebViewFactory { newVmSize = Math.max(newVmSize, f.length()); continue; } - if (path.contains("!")) { - String[] split = TextUtils.split(path, "!"); + if (path.contains("!/")) { + String[] split = TextUtils.split(path, "!/"); if (split.length == 2) { try { ZipFile z = new ZipFile(split[0]); @@ -384,7 +384,7 @@ public final class WebViewFactory { ZipEntry e = z.getEntry(entry); if (e != null && e.getMethod() == ZipEntry.STORED) { // Return a path formatted for dlopen() load from APK. - return apkPath + "!" + entry; + return apkPath + "!/" + entry; } } } catch (IOException e) { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index e43237a..cf6a018 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1162,6 +1162,10 @@ public class Editor { // We do not hide the span controllers, since they can be added when a new text is // inserted into the text view (voice IME). hideCursorControllers(); + // Reset drag accelerator. + if (mSelectionModifierCursorController != null) { + mSelectionModifierCursorController.resetTouchOffsets(); + } stopTextActionMode(); } diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index f06f3c2..11d7026 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -662,7 +662,7 @@ class FastScroller { final int adjMaxWidth = maxWidth - marginLeft - marginRight; final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); - final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(), + final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(), MeasureSpec.UNSPECIFIED); view.measure(widthMeasureSpec, heightMeasureSpec); @@ -702,7 +702,7 @@ class FastScroller { final int containerWidth = container.width(); final int adjMaxWidth = containerWidth - marginLeft - marginRight; final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST); - final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(), + final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(), MeasureSpec.UNSPECIFIED); preview.measure(widthMeasureSpec, heightMeasureSpec); @@ -768,7 +768,7 @@ class FastScroller { final Rect container = mContainerRect; final int maxWidth = container.width(); final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); - final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(), + final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(), MeasureSpec.UNSPECIFIED); track.measure(widthMeasureSpec, heightMeasureSpec); diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index dcaafa5..f994d4a 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1073,7 +1073,7 @@ public class GridView extends AbsListView { p.forceAdd = true; int childHeightSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), + MeasureSpec.makeSafeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED), 0, p.height); int childWidthSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width); diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 9d14254..056323d 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -1062,9 +1062,9 @@ public class LinearLayout extends ViewGroup { // use as much space as it wants because we can shrink things // later (and re-measure). if (baselineAligned) { - final int freeWidthSpec = MeasureSpec.makeMeasureSpec( + final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED); - final int freeHeightSpec = MeasureSpec.makeMeasureSpec( + final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(freeWidthSpec, freeHeightSpec); } else { diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index f8b965f..fd0395a 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1206,7 +1206,7 @@ public class ListView extends AbsListView { if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { - childHeightSpec = MeasureSpec.makeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED); + childHeightSpec = MeasureSpec.makeSafeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } @@ -1943,7 +1943,7 @@ public class ListView extends AbsListView { if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { - childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), + childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); @@ -2698,7 +2698,7 @@ public class ListView extends AbsListView { if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { - childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), + childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 11904e1..58a94b9 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -1263,7 +1263,7 @@ public class ScrollView extends FrameLayout { childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); - childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); @@ -1277,7 +1277,7 @@ public class ScrollView extends FrameLayout { final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); - final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index 6fe34dd..fdabe91 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -812,9 +812,9 @@ public class Spinner extends AbsSpinner implements OnClickListener { View itemView = null; int itemType = 0; final int widthMeasureSpec = - MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED); + MeasureSpec.makeSafeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED); final int heightMeasureSpec = - MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED); + MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED); // Make sure the number of items we'll measure is capped. If it's a huge data set // with wildly varying sizes, oh well. diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index aa7168c..d9cff4e 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -174,7 +174,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { // First, measure with no constraint final int width = MeasureSpec.getSize(widthMeasureSpec); - final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); + final int unspecifiedWidth = MeasureSpec.makeSafeMeasureSpec(width, + MeasureSpec.UNSPECIFIED); mImposedTabsHeight = -1; super.measureHorizontal(unspecifiedWidth, heightMeasureSpec); diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java index d4288d6..f7f9c91 100644 --- a/core/java/android/widget/TableRow.java +++ b/core/java/android/widget/TableRow.java @@ -303,7 +303,7 @@ public class TableRow extends LinearLayout { spec = getChildMeasureSpec(widthMeasureSpec, 0, LayoutParams.WRAP_CONTENT); break; case LayoutParams.MATCH_PARENT: - spec = MeasureSpec.makeMeasureSpec( + spec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED); break; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 353901c..78b5d5d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8790,7 +8790,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onProvideStructure(ViewStructure structure) { super.onProvideStructure(structure); - final boolean isPassword = hasPasswordTransformationMethod(); + final boolean isPassword = hasPasswordTransformationMethod() + || isPasswordInputType(getInputType()); if (!isPassword) { structure.setText(getText(), getSelectionStart(), getSelectionEnd()); @@ -9244,25 +9245,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * If provided, this ActionMode.Callback will be used to create the ActionMode when text * insertion is initiated in this View. - * * The standard implementation populates the menu with a subset of Select All, * Paste and Replace actions, depending on what this View supports. * - * A custom implementation can add new entries in the default menu in its - * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The - * default actions can also be removed from the menu using + * <p>A custom implementation can add new entries in the default menu in its + * {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode, + * android.view.Menu)} method. The default actions can also be removed from the menu using * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, - * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters. + * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p> * - * Returning false from - * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent - * the action mode from being started. + * <p>Returning false from + * {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode, + * android.view.Menu)} will prevent the action mode from being started.</p> * - * Action click events should be handled by the custom implementation of - * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}. + * <p>Action click events should be handled by the custom implementation of + * {@link android.view.ActionMode.Callback#onActionItemClicked(android.view.ActionMode, + * android.view.MenuItem)}.</p> * - * Note that text insertion mode is not started when a TextView receives focus and the - * {@link android.R.attr#selectAllOnFocus} flag has been set. + * <p>Note that text insertion mode is not started when a TextView receives focus and the + * {@link android.R.attr#selectAllOnFocus} flag has been set.</p> */ public void setCustomInsertionActionModeCallback(ActionMode.Callback actionModeCallback) { createEditorIfNeeded(); diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 42668f1..585cdf1 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -45,7 +45,7 @@ import java.util.Map; class ResolverComparator implements Comparator<ResolvedComponentInfo> { private static final String TAG = "ResolverComparator"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; // Two weeks private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java index 7ae7d0f..05cfd81 100644 --- a/core/java/com/android/internal/app/WindowDecorActionBar.java +++ b/core/java/com/android/internal/app/WindowDecorActionBar.java @@ -47,7 +47,6 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.ActionMode; -import android.view.ActionMode.Callback; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.Menu; @@ -106,6 +105,10 @@ public class WindowDecorActionBar extends ActionBar implements private static final int INVALID_POSITION = -1; + // The fade duration for toolbar and action bar when entering/exiting action mode. + private static final long FADE_OUT_DURATION_MS = 100; + private static final long FADE_IN_DURATION_MS = 200; + private int mContextDisplayMode; private boolean mHasEmbeddedTabs; @@ -866,8 +869,21 @@ public class WindowDecorActionBar extends ActionBar implements hideForActionMode(); } - mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); - mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); + Animator fadeIn, fadeOut; + if (toActionMode) { + fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE, + FADE_OUT_DURATION_MS); + fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE, + FADE_IN_DURATION_MS); + } else { + fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE, + FADE_IN_DURATION_MS); + fadeOut = mContextView.setupAnimatorToVisibility(View.GONE, + FADE_OUT_DURATION_MS); + } + AnimatorSet set = new AnimatorSet(); + set.playSequentially(fadeOut, fadeIn); + set.start(); // mTabScrollView's visibility is not affected by action mode. } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index 4290e22..6a85afb 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -587,6 +587,7 @@ public final class BatteryStatsHelper { bs.add(wbs); } bs.computeMobilemspp(); + bs.sumPower(); } private void addIdleUsage() { @@ -612,9 +613,8 @@ public final class BatteryStatsHelper { private void addWiFiUsage() { BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0); mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType); - bs.sumPower(); - if (bs.totalPowerMah > 0 || !mWifiSippers.isEmpty()) { - aggregateSippers(bs, mWifiSippers, "WIFI"); + aggregateSippers(bs, mWifiSippers, "WIFI"); + if (bs.totalPowerMah > 0) { mUsageList.add(bs); } } @@ -627,8 +627,8 @@ public final class BatteryStatsHelper { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0); mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType); - if (bs.sumPower() > 0) { - aggregateSippers(bs, mBluetoothSippers, "Bluetooth"); + aggregateSippers(bs, mBluetoothSippers, "Bluetooth"); + if (bs.totalPowerMah > 0) { mUsageList.add(bs); } } @@ -639,7 +639,6 @@ public final class BatteryStatsHelper { BatterySipper bs = new BatterySipper(DrainType.USER, null, 0); bs.userId = userId; aggregateSippers(bs, mUserSippers.valueAt(i), "User"); - bs.sumPower(); mUsageList.add(bs); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 087db78..07d1fc8 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -4634,7 +4634,7 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtimeMs) { int bin = 0; - while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) { + while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS-1) { csph = csph >> 3; bin++; } diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java index 850ea23..35eeca7 100644 --- a/core/java/com/android/internal/widget/AbsActionBarView.java +++ b/core/java/com/android/internal/widget/AbsActionBarView.java @@ -136,10 +136,11 @@ public abstract class AbsActionBarView extends ViewGroup { return getVisibility(); } - public void animateToVisibility(int visibility) { + public Animator setupAnimatorToVisibility(int visibility, long duration) { if (mVisibilityAnim != null) { mVisibilityAnim.cancel(); } + if (visibility == VISIBLE) { if (getVisibility() != VISIBLE) { setAlpha(0); @@ -147,38 +148,43 @@ public abstract class AbsActionBarView extends ViewGroup { mMenuView.setAlpha(0); } } - ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); - anim.setDuration(FADE_DURATION); + ObjectAnimator anim = ObjectAnimator.ofFloat(this, View.ALPHA, 1); + anim.setDuration(duration); anim.setInterpolator(sAlphaInterpolator); if (mSplitView != null && mMenuView != null) { AnimatorSet set = new AnimatorSet(); - ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1); - splitAnim.setDuration(FADE_DURATION); + ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, View.ALPHA, 1); + splitAnim.setDuration(duration); set.addListener(mVisAnimListener.withFinalVisibility(visibility)); set.play(anim).with(splitAnim); - set.start(); + return set; } else { anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); - anim.start(); + return anim; } } else { - ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); - anim.setDuration(FADE_DURATION); + ObjectAnimator anim = ObjectAnimator.ofFloat(this, View.ALPHA, 0); + anim.setDuration(duration); anim.setInterpolator(sAlphaInterpolator); if (mSplitView != null && mMenuView != null) { AnimatorSet set = new AnimatorSet(); - ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0); - splitAnim.setDuration(FADE_DURATION); + ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, View.ALPHA, 0); + splitAnim.setDuration(duration); set.addListener(mVisAnimListener.withFinalVisibility(visibility)); set.play(anim).with(splitAnim); - set.start(); + return set; } else { anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); - anim.start(); + return anim; } } } + public void animateToVisibility(int visibility) { + Animator anim = setupAnimatorToVisibility(visibility, FADE_DURATION); + anim.start(); + } + @Override public void setVisibility(int visibility) { if (visibility != getVisibility()) { diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index 106272b..693b194 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -21,10 +21,6 @@ import android.widget.ActionMenuPresenter; import android.widget.ActionMenuView; import com.android.internal.view.menu.MenuBuilder; -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; @@ -35,14 +31,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; -import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; import android.widget.TextView; /** * @hide */ -public class ActionBarContextView extends AbsActionBarView implements AnimatorListener { +public class ActionBarContextView extends AbsActionBarView { private static final String TAG = "ActionBarContextView"; private CharSequence mTitle; @@ -59,14 +54,6 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi private boolean mTitleOptional; private int mCloseItemLayout; - private Animator mCurrentAnimation; - private boolean mAnimateInOnLayout; - private int mAnimationMode; - - private static final int ANIMATE_IDLE = 0; - private static final int ANIMATE_IN = 1; - private static final int ANIMATE_OUT = 2; - public ActionBarContextView(Context context) { this(context, null); } @@ -255,43 +242,23 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi mMenuView.setBackgroundDrawable(mSplitBackground); mSplitView.addView(mMenuView, layoutParams); } - - mAnimateInOnLayout = true; } public void closeMode() { - if (mAnimationMode == ANIMATE_OUT) { - // Called again during close; just finish what we were doing. - return; - } if (mClose == null) { killMode(); return; } - finishAnimation(); - mAnimationMode = ANIMATE_OUT; - mCurrentAnimation = makeOutAnimation(); - mCurrentAnimation.start(); - } - - private void finishAnimation() { - final Animator a = mCurrentAnimation; - if (a != null) { - mCurrentAnimation = null; - a.end(); - } } public void killMode() { - finishAnimation(); removeAllViews(); if (mSplitView != null) { mSplitView.removeView(mMenuView); } mCustomView = null; mMenuView = null; - mAnimateInOnLayout = false; } @Override @@ -343,7 +310,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + "with android:layout_height=\"wrap_content\""); } - + final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); int maxHeight = mContentHeight > 0 ? @@ -353,7 +320,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); final int height = maxHeight - verticalPadding; final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); - + if (mClose != null) { availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0); MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams(); @@ -367,7 +334,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi if (mTitleLayout != null && mCustomView == null) { if (mTitleOptional) { - final int titleWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth, + final int titleWidthSpec = MeasureSpec.makeSafeMeasureSpec(contentWidth, MeasureSpec.UNSPECIFIED); mTitleLayout.measure(titleWidthSpec, childSpecHeight); final int titleWidth = mTitleLayout.getMeasuredWidth(); @@ -411,66 +378,13 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi } } - private Animator makeInAnimation() { - mClose.setTranslationX(-mClose.getWidth() - - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); - ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0); - buttonAnimator.setDuration(200); - buttonAnimator.addListener(this); - buttonAnimator.setInterpolator(new DecelerateInterpolator()); - - AnimatorSet set = new AnimatorSet(); - AnimatorSet.Builder b = set.play(buttonAnimator); - - if (mMenuView != null) { - final int count = mMenuView.getChildCount(); - if (count > 0) { - for (int i = count - 1, j = 0; i >= 0; i--, j++) { - View child = mMenuView.getChildAt(i); - child.setScaleY(0); - ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1); - a.setDuration(300); - b.with(a); - } - } - } - - return set; - } - - private Animator makeOutAnimation() { - ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", - -mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); - buttonAnimator.setDuration(200); - buttonAnimator.addListener(this); - buttonAnimator.setInterpolator(new DecelerateInterpolator()); - - AnimatorSet set = new AnimatorSet(); - AnimatorSet.Builder b = set.play(buttonAnimator); - - if (mMenuView != null) { - final int count = mMenuView.getChildCount(); - if (count > 0) { - for (int i = 0; i < 0; i++) { - View child = mMenuView.getChildAt(i); - child.setScaleY(0); - ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0); - a.setDuration(300); - b.with(a); - } - } - } - - return set; - } - @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final boolean isLayoutRtl = isLayoutRtl(); int x = isLayoutRtl ? r - l - getPaddingRight() : getPaddingLeft(); final int y = getPaddingTop(); final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); - + if (mClose != null && mClose.getVisibility() != GONE) { MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams(); final int startMargin = (isLayoutRtl ? lp.rightMargin : lp.leftMargin); @@ -479,12 +393,6 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi x += positionChild(mClose, x, y, contentHeight, isLayoutRtl); x = next(x, endMargin, isLayoutRtl); - if (mAnimateInOnLayout) { - mAnimationMode = ANIMATE_IN; - mCurrentAnimation = makeInAnimation(); - mCurrentAnimation.start(); - mAnimateInOnLayout = false; - } } if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) { @@ -503,26 +411,6 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi } @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - if (mAnimationMode == ANIMATE_OUT) { - killMode(); - } - mAnimationMode = ANIMATE_IDLE; - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override public boolean shouldDelayChildPressedState() { return false; } diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java index fb413b5..fe70d7b 100644 --- a/core/java/com/android/internal/widget/DecorToolbar.java +++ b/core/java/com/android/internal/widget/DecorToolbar.java @@ -17,6 +17,7 @@ package com.android.internal.widget; +import android.animation.Animator; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Parcelable; @@ -87,6 +88,7 @@ public interface DecorToolbar { void setCustomView(View view); View getCustomView(); void animateToVisibility(int visibility); + Animator setupAnimatorToVisibility(int visibility, long duration); void setNavigationIcon(Drawable icon); void setNavigationIcon(int resId); void setNavigationContentDescription(CharSequence description); diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java index 0066ed0..79adada 100644 --- a/core/java/com/android/internal/widget/SlidingTab.java +++ b/core/java/com/android/internal/widget/SlidingTab.java @@ -403,10 +403,10 @@ public class SlidingTab extends ViewGroup { public void measure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); - tab.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED), - View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED)); - text.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED), - View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED)); + tab.measure(View.MeasureSpec.makeSafeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeSafeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED)); + text.measure(View.MeasureSpec.makeSafeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeSafeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED)); } /** diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java index 54df87b..32aae72 100644 --- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java +++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java @@ -19,6 +19,7 @@ package com.android.internal.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; @@ -59,6 +60,8 @@ public class ToolbarWidgetWrapper implements DecorToolbar { private static final int AFFECTS_LOGO_MASK = ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO; + // Default fade duration for fading in/out tool bar. + private static final long DEFAULT_FADE_DURATION_MS = 200; private Toolbar mToolbar; @@ -571,9 +574,19 @@ public class ToolbarWidgetWrapper implements DecorToolbar { @Override public void animateToVisibility(int visibility) { + Animator anim = setupAnimatorToVisibility(visibility, DEFAULT_FADE_DURATION_MS); + if (anim != null) { + anim.start(); + } + } + + @Override + public Animator setupAnimatorToVisibility(int visibility, long duration) { + if (visibility == View.GONE) { - mToolbar.animate().alpha(0) - .setListener(new AnimatorListenerAdapter() { + ObjectAnimator anim = ObjectAnimator.ofFloat(mToolbar, View.ALPHA, 1, 0); + anim.setDuration(duration); + anim.addListener(new AnimatorListenerAdapter() { private boolean mCanceled = false; @Override public void onAnimationEnd(Animator animation) { @@ -587,15 +600,19 @@ public class ToolbarWidgetWrapper implements DecorToolbar { mCanceled = true; } }); + return anim; } else if (visibility == View.VISIBLE) { - mToolbar.animate().alpha(1) - .setListener(new AnimatorListenerAdapter() { + ObjectAnimator anim = ObjectAnimator.ofFloat(mToolbar, View.ALPHA, 0, 1); + anim.setDuration(duration); + anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mToolbar.setVisibility(View.VISIBLE); } }); + return anim; } + return null; } @Override |
