diff options
Diffstat (limited to 'core/java')
61 files changed, 1163 insertions, 576 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 480d171..ffa36d6 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -207,8 +207,7 @@ public class AccountManager { * were authenticated successfully. Time is specified in milliseconds since * epoch. */ - public static final String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = - "lastAuthenticatedTimeMillisEpoch"; + public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime"; /** * Authenticators using 'customTokens' option will also get the UID of the @@ -671,8 +670,8 @@ public class AccountManager { } /** - * Informs the system that the account has been authenticated recently. This - * recency may be used by other applications to verify the account. This + * Notifies the system that the account has just been authenticated. This + * information may be used by other applications to verify the account. This * should be called only when the user has entered correct credentials for * the account. * <p> @@ -685,7 +684,7 @@ public class AccountManager { * * @param account The {@link Account} to be updated. */ - public boolean accountAuthenticated(Account account) { + public boolean notifyAccountAuthenticated(Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -1587,7 +1586,7 @@ public class AccountManager { * password prompt. * * <p>Also the returning Bundle may contain {@link - * #KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH} indicating the last time the + * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the * credential was validated/created. * * If an error occurred,{@link AccountManagerFuture#getResult()} throws: diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9bad9bb..2e45b79 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -114,7 +114,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.net.InetAddress; -import java.security.Security; import java.text.DateFormat; import java.util.ArrayList; import java.util.List; @@ -5338,7 +5337,7 @@ public final class ActivityThread { // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); - Security.addProvider(new AndroidKeyStoreProvider()); + AndroidKeyStoreProvider.install(); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 223d528..1127436 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -221,8 +221,7 @@ public class AppOpsManager { public static final int _NUM_OP = 53; /** Access to coarse location information. */ - public static final String OPSTR_COARSE_LOCATION = - "android:coarse_location"; + public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; /** Access to fine location information. */ public static final String OPSTR_FINE_LOCATION = "android:fine_location"; @@ -237,7 +236,59 @@ public class AppOpsManager { = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi - public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; + public static final String OPSTR_ACTIVATE_VPN + = "android:activate_vpn"; + /** @hide Allows an application to read the user's contacts data. */ + public static final String OPSTR_READ_CONTACTS + = "android:read_contacts"; + /** @hide Allows an application to write to the user's contacts data. */ + public static final String OPSTR_WRITE_CONTACTS + = "android:write_contacts"; + /** @hide Allows an application to read the user's call log. */ + public static final String OPSTR_READ_CALL_LOG + = "android:read_call_log"; + /** @hide Allows an application to write to the user's call log. */ + public static final String OPSTR_WRITE_CALL_LOG + = "android:write_call_log"; + /** @hide Allows an application to read the user's calendar data. */ + public static final String OPSTR_READ_CALENDAR + = "android:read_calendar"; + /** @hide Allows an application to write to the user's calendar data. */ + public static final String OPSTR_WRITE_CALENDAR + = "android:write_calendar"; + /** @hide Allows an application to initiate a phone call. */ + public static final String OPSTR_CALL_PHONE + = "android:call_phone"; + /** @hide Allows an application to read SMS messages. */ + public static final String OPSTR_READ_SMS + = "android:read_sms"; + /** @hide Allows an application to receive SMS messages. */ + public static final String OPSTR_RECEIVE_SMS + = "android:receive_sms"; + /** @hide Allows an application to receive MMS messages. */ + public static final String OPSTR_RECEIVE_MMS + = "android:receive_mms"; + /** @hide Allows an application to receive WAP push messages. */ + public static final String OPSTR_RECEIVE_WAP_PUSH + = "android:receive_wap_push"; + /** @hide Allows an application to send SMS messages. */ + public static final String OPSTR_SEND_SMS + = "android:send_sms"; + /** @hide Allows an application to add system alert windows. */ + public static final String OPSTR_SYSTEM_ALERT_WINDOW + = "android:system_alert_window"; + /** @hide Required to be able to access the camera device. */ + public static final String OPSTR_CAMERA + = "android:camera"; + /** @hide Required to be able to access the microphone device. */ + public static final String OPSTR_RECORD_AUDIO + = "android:record_audio"; + /** @hide Required to access phone state related information. */ + public static final String OPSTR_READ_PHONE_STATE + = "android:read_phone_state"; + /** @hide Required to access phone state related information. */ + public static final String OPSTR_ADD_VOICEMAIL + = "android:add_voicemail"; /** * This maps each operation to the operation that serves as the @@ -726,6 +777,33 @@ public class AppOpsManager { false }; + /** + * This is a mapping from a permission name to public app op name. + */ + private static final ArrayMap<String, String> sPermToOp = new ArrayMap<>(); + static { + sPermToOp.put(Manifest.permission.ACCESS_COARSE_LOCATION, OPSTR_COARSE_LOCATION); + sPermToOp.put(Manifest.permission.ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION); + sPermToOp.put(Manifest.permission.PACKAGE_USAGE_STATS, OPSTR_GET_USAGE_STATS); + sPermToOp.put(Manifest.permission.READ_CONTACTS, OPSTR_READ_CONTACTS); + sPermToOp.put(Manifest.permission.WRITE_CONTACTS, OPSTR_WRITE_CONTACTS); + sPermToOp.put(Manifest.permission.READ_CALL_LOG, OPSTR_READ_CALL_LOG); + sPermToOp.put(Manifest.permission.WRITE_CALL_LOG, OPSTR_WRITE_CALL_LOG); + sPermToOp.put(Manifest.permission.READ_CALENDAR, OPSTR_READ_CALENDAR); + sPermToOp.put(Manifest.permission.WRITE_CALENDAR, OPSTR_WRITE_CALENDAR); + sPermToOp.put(Manifest.permission.CALL_PHONE, OPSTR_CALL_PHONE); + sPermToOp.put(Manifest.permission.READ_SMS, OPSTR_READ_SMS); + sPermToOp.put(Manifest.permission.RECEIVE_SMS, OPSTR_RECEIVE_SMS); + sPermToOp.put(Manifest.permission.RECEIVE_MMS, OPSTR_RECEIVE_MMS); + sPermToOp.put(Manifest.permission.RECEIVE_WAP_PUSH, OPSTR_RECEIVE_WAP_PUSH); + sPermToOp.put(Manifest.permission.SEND_SMS, OPSTR_SEND_SMS); + sPermToOp.put(Manifest.permission.SYSTEM_ALERT_WINDOW, OPSTR_SYSTEM_ALERT_WINDOW); + sPermToOp.put(Manifest.permission.CAMERA, OPSTR_CAMERA); + sPermToOp.put(Manifest.permission.RECORD_AUDIO, OPSTR_RECORD_AUDIO); + sPermToOp.put(Manifest.permission.READ_PHONE_STATE, OPSTR_READ_PHONE_STATE); + sPermToOp.put(Manifest.permission.ADD_VOICEMAIL, OPSTR_ADD_VOICEMAIL); + } + private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); static { @@ -1066,6 +1144,21 @@ public class AppOpsManager { } /** + * Gets the app op name associated with a given permission. + * The app op name is one of the public constants defined + * in this class such as {@link #OPSTR_COARSE_LOCATION}. + * + * @param permission The permission. + * @return The app op associated with the permission or null. + * + * @hide + */ + @SystemApi + public static String permissionToOp(String permission) { + return sPermToOp.get(permission); + } + + /** * Monitor for changes to the operating mode for the given op in the given app package. * @param op The operation to monitor, one of OPSTR_*. * @param packageName The name of the application to monitor. diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 16a2430..90293a4 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -62,6 +62,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -79,6 +80,7 @@ import android.view.Display; import dalvik.system.VMRuntime; import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.SomeArgs; import com.android.internal.util.Preconditions; import com.android.internal.util.UserIcons; @@ -1560,13 +1562,7 @@ final class ApplicationPackageManager extends PackageManager { public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() { final StorageManager storage = mContext.getSystemService(StorageManager.class); final String volumeUuid = storage.getPrimaryStorageUuid(); - if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { - return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); - } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { - return storage.getPrimaryPhysicalVolume(); - } else { - return storage.findVolumeByUuid(volumeUuid); - } + return storage.findVolumeByQualifiedUuid(volumeUuid); } @Override @@ -2054,7 +2050,7 @@ final class ApplicationPackageManager extends PackageManager { /** {@hide} */ private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements Handler.Callback { - private static final int MSG_STARTED = 1; + private static final int MSG_CREATED = 1; private static final int MSG_STATUS_CHANGED = 2; final MoveCallback mCallback; @@ -2067,26 +2063,38 @@ final class ApplicationPackageManager extends PackageManager { @Override public boolean handleMessage(Message msg) { - final int moveId = msg.arg1; switch (msg.what) { - case MSG_STARTED: - mCallback.onStarted(moveId, (String) msg.obj); + case MSG_CREATED: { + final SomeArgs args = (SomeArgs) msg.obj; + mCallback.onCreated(args.argi1, (Bundle) args.arg2); + args.recycle(); return true; - case MSG_STATUS_CHANGED: - mCallback.onStatusChanged(moveId, msg.arg2, (long) msg.obj); + } + case MSG_STATUS_CHANGED: { + final SomeArgs args = (SomeArgs) msg.obj; + mCallback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3); + args.recycle(); return true; + } } return false; } @Override - public void onStarted(int moveId, String title) { - mHandler.obtainMessage(MSG_STARTED, moveId, 0, title).sendToTarget(); + public void onCreated(int moveId, Bundle extras) { + final SomeArgs args = SomeArgs.obtain(); + args.argi1 = moveId; + args.arg2 = extras; + mHandler.obtainMessage(MSG_CREATED, args).sendToTarget(); } @Override public void onStatusChanged(int moveId, int status, long estMillis) { - mHandler.obtainMessage(MSG_STATUS_CHANGED, moveId, status, estMillis).sendToTarget(); + final SomeArgs args = SomeArgs.obtain(); + args.argi1 = moveId; + args.argi2 = status; + args.arg3 = estMillis; + mHandler.obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget(); } } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index ebb3c43..2c12317 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -199,9 +199,12 @@ public class KeyguardManager { } /** - * Return whether the keyguard requires a password to unlock. + * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card + * is currently locked. * - * @return true if keyguard is secure. + * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states. + * + * @return true if a PIN, pattern or password is set or a SIM card is locked. */ public boolean isKeyguardSecure() { try { @@ -240,12 +243,8 @@ public class KeyguardManager { } /** - * Returns whether the device is currently locked and requires a PIN, pattern or - * password to unlock. + * Per-user version of {@link #isDeviceLocked()}. * - * @param userId the user for which the locked state should be reported. - * @return true if unlocking the device currently requires a PIN, pattern or - * password. * @hide */ public boolean isDeviceLocked(int userId) { @@ -260,6 +259,8 @@ public class KeyguardManager { * Returns whether the device is secured with a PIN, pattern or * password. * + * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure. + * * @return true if a PIN, pattern or password was set. */ public boolean isDeviceSecure() { @@ -267,11 +268,8 @@ public class KeyguardManager { } /** - * Returns whether the device is secured with a PIN, pattern or - * password. + * Per-user version of {@link #isDeviceSecure()}. * - * @param userId the user for which the secure state should be reported. - * @return true if a PIN, pattern or password was set. * @hide */ public boolean isDeviceSecure(int userId) { diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 207519c..31d1ab7 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -63,12 +63,20 @@ public class StatusBarManager { | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK | DISABLE_SEARCH; + /** + * Flag to disable quick settings. + * + * Setting this flag disables quick settings completely, but does not disable expanding the + * notification shade. + */ + public static final int DISABLE2_QUICK_SETTINGS = 0x00000001; + public static final int DISABLE2_NONE = 0x00000000; - public static final int DISABLE2_MASK = 0x00000000; + public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS; @IntDef(flag = true, - value = {DISABLE2_NONE, DISABLE2_MASK}) + value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS}) @Retention(RetentionPolicy.SOURCE) public @interface Disable2Flags {} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ed814c3..cf9813f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -807,6 +807,24 @@ public class DevicePolicyManager { public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED"; + /** + * Permission policy to prompt user for new permission requests for runtime permissions. + * Already granted or denied permissions are not affected by this. + */ + public static final int PERMISSION_POLICY_PROMPT = 0; + + /** + * Permission policy to always grant new permission requests for runtime permissions. + * Already granted or denied permissions are not affected by this. + */ + public static final int PERMISSION_POLICY_AUTO_GRANT = 1; + + /** + * Permission policy to always deny new permission requests for runtime permissions. + * Already granted or denied permissions are not affected by this. + */ + public static final int PERMISSION_POLICY_AUTO_DENY = 2; + /** * Return true if the given administrator component is currently @@ -4342,4 +4360,58 @@ public class DevicePolicyManager { Log.w(TAG, "Failed talking with device policy service", re); } } + + /** + * Called by profile or device owners to set the default response for future runtime permission + * requests by applications. The policy can allow for normal operation which prompts the + * user to grant a permission, or can allow automatic granting or denying of runtime + * permission requests by an application. This also applies to new permissions declared by app + * updates. + * @param admin Which profile or device owner this request is associated with. + * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT}, + * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}. + */ + public void setPermissionPolicy(ComponentName admin, int policy) { + try { + mService.setPermissionPolicy(admin, policy); + } catch (RemoteException re) { + Log.w(TAG, "Failed talking with device policy service", re); + } + } + + /** + * Returns the current runtime permission policy set by the device or profile owner. The + * default is {@link #PERMISSION_POLICY_PROMPT}. + * @param admin Which profile or device owner this request is associated with. + * @return the current policy for future permission requests. + */ + public int getPermissionPolicy(ComponentName admin) { + try { + return mService.getPermissionPolicy(admin); + } catch (RemoteException re) { + return PERMISSION_POLICY_PROMPT; + } + } + + /** + * Grants or revokes a runtime permission to a specific application so that the user + * does not have to be prompted. This might affect all permissions in a group that the + * runtime permission belongs to. This method can only be called by a profile or device + * owner. + * @param admin Which profile or device owner this request is associated with. + * @param packageName The application to grant or revoke a permission to. + * @param permission The permission to grant or revoke. + * @param granted Whether or not to grant the permission. If false, all permissions in the + * associated permission group will be denied. + * @return whether the permission was successfully granted or revoked + */ + public boolean setPermissionGranted(ComponentName admin, String packageName, + String permission, boolean granted) { + try { + return mService.setPermissionGranted(admin, packageName, permission, granted); + } catch (RemoteException re) { + Log.w(TAG, "Failed talking with device policy service", re); + return false; + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index a678c51..833bc00 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -229,4 +229,9 @@ interface IDevicePolicyManager { boolean getDoNotAskCredentialsOnBoot(); void notifyPendingSystemUpdate(in long updateReceivedTime); + + void setPermissionPolicy(in ComponentName admin, int policy); + int getPermissionPolicy(in ComponentName admin); + boolean setPermissionGranted(in ComponentName admin, String packageName, String permission, + boolean granted); } diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java index f103cae..123514e 100644 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ b/core/java/android/bluetooth/le/ScanSettings.java @@ -236,7 +236,7 @@ public final class ScanSettings implements Parcelable { private int mScanResultType = SCAN_RESULT_TYPE_FULL; private long mReportDelayMillis = 0; private int mMatchMode = MATCH_MODE_AGGRESSIVE; - private int mNumOfMatchesPerFilter = MATCH_NUM_ONE_ADVERTISEMENT; + private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT; /** * Set scan mode for Bluetooth LE scan. * diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index f2e7fc4..4769bd0 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -593,7 +593,8 @@ final class ContentProviderProxy implements IContentProvider DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); int has = reply.readInt(); - ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; + ParcelFileDescriptor fd = has != 0 ? ParcelFileDescriptor.CREATOR + .createFromParcel(reply) : null; return fd; } finally { data.recycle(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5eacce3..8687c6b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -252,6 +252,21 @@ public abstract class Context { public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080; /** + * @hide Flag for {@link #bindService}: Like {@link #BIND_FOREGROUND_SERVICE}, + * but only applies while the device is awake. + */ + public static final int BIND_FOREGROUND_SERVICE_WHILE_AWAKE = 0x02000000; + + /** + * @hide Flag for {@link #bindService}: For only the case where the binding + * is coming from the system, set the process state to FOREGROUND_SERVICE + * instead of the normal maximum of IMPORTANT_FOREGROUND. That is, this is + * saying that the process shouldn't participate in the normal power reduction + * modes (removing network access etc). + */ + public static final int BIND_FOREGROUND_SERVICE = 0x04000000; + + /** * @hide Flag for {@link #bindService}: Treat the binding as hosting * an activity, an unbinding as the activity going in the background. * That is, when unbinding, the process when empty will go on the activity @@ -374,24 +389,30 @@ public abstract class Context { } /** - * Return a localized string from the application's package's + * Returns a localized string from the application's package's * default string table. * * @param resId Resource id for the string + * @return The string data associated with the resource, stripped of styled + * text information. */ + @NonNull public final String getString(@StringRes int resId) { return getResources().getString(resId); } /** - * Return a localized formatted string from the application's package's + * Returns a localized formatted string from the application's package's * default string table, substituting the format arguments as defined in * {@link java.util.Formatter} and {@link java.lang.String#format}. * * @param resId Resource id for the format string - * @param formatArgs The format arguments that will be used for substitution. + * @param formatArgs The format arguments that will be used for + * substitution. + * @return The string data associated with the resource, formatted and + * stripped of styled text information. */ - + @NonNull public final String getString(@StringRes int resId, Object... formatArgs) { return getResources().getString(resId, formatArgs); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index ae59bfc..0b24594 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -58,6 +58,7 @@ import android.content.IntentSender; * {@hide} */ interface IPackageManager { + boolean isPackageFrozen(String packageName); boolean isPackageAvailable(String packageName, int userId); PackageInfo getPackageInfo(String packageName, int flags, int userId); int getPackageUid(String packageName, int userId); diff --git a/core/java/android/content/pm/IPackageMoveObserver.aidl b/core/java/android/content/pm/IPackageMoveObserver.aidl index 50ab3b5..86189fc 100644 --- a/core/java/android/content/pm/IPackageMoveObserver.aidl +++ b/core/java/android/content/pm/IPackageMoveObserver.aidl @@ -17,11 +17,13 @@ package android.content.pm; +import android.os.Bundle; + /** * Callback for moving package resources from the Package Manager. * @hide */ oneway interface IPackageMoveObserver { - void onStarted(int moveId, String title); + void onCreated(int moveId, in Bundle extras); void onStatusChanged(int moveId, int status, long estMillis); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e1c271d..7ff6ec3 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -209,7 +209,14 @@ public abstract class PackageManager { * matching. This is a synonym for including the CATEGORY_DEFAULT in your * supplied Intent. */ - public static final int MATCH_DEFAULT_ONLY = 0x00010000; + public static final int MATCH_DEFAULT_ONLY = 0x00010000; + + /** + * Querying flag: if set and if the platform is doing any filtering of the results, then + * the filtering will not happen. This is a synonym for saying that all results should + * be returned. + */ + public static final int MATCH_ALL = 0x00020000; /** * Flag for {@link addCrossProfileIntentFilter}: if this flag is set: @@ -2637,6 +2644,8 @@ public abstract class PackageManager { * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. * + * You can also set {@link #MATCH_ALL} for preventing the filtering of the results. + * * @return A List<ResolveInfo> containing one entry for each matching * Activity. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by @@ -2658,6 +2667,8 @@ public abstract class PackageManager { * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. * + * You can also set {@link #MATCH_ALL} for preventing the filtering of the results. + * * @return A List<ResolveInfo> containing one entry for each matching * Activity. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by @@ -4201,7 +4212,7 @@ public abstract class PackageManager { /** {@hide} */ public static abstract class MoveCallback { - public abstract void onStarted(int moveId, String title); + public void onCreated(int moveId, Bundle extras) {} public abstract void onStatusChanged(int moveId, int status, long estMillis); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index fed9261..9596c42 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4315,9 +4315,6 @@ public class PackageParser { // Additional data supplied by callers. public Object mExtras; - // Whether an operation is currently pending on this package - public boolean mOperationPending; - // Applications hardware preferences public ArrayList<ConfigurationInfo> configPreferences = null; diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index fdafb04..14bfac5 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -271,7 +271,7 @@ public class ColorStateList implements Parcelable { final TypedArray a = Resources.obtainAttributes(r, theme, attrs, R.styleable.ColorStateListItem); final int[] themeAttrs = a.extractThemeAttrs(); - final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, 0); + final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, Color.MAGENTA); final float alphaMod = a.getFloat(R.styleable.ColorStateListItem_alpha, 1.0f); changingConfigurations |= a.getChangingConfigurations(); @@ -296,7 +296,9 @@ public class ColorStateList implements Parcelable { } stateSpec = StateSet.trimStateSet(stateSpec, j); - // Apply alpha modulation. + // Apply alpha modulation. If we couldn't resolve the color or + // alpha yet, the default values leave us enough information to + // modulate again during applyTheme(). final int color = modulateColorAlpha(baseColor, alphaMod); if (listSize == 0 || stateSpec.length == 0) { defaultColor = color; @@ -365,14 +367,31 @@ public class ColorStateList implements Parcelable { if (themeAttrsList[i] != null) { final TypedArray a = t.resolveAttributes(themeAttrsList[i], R.styleable.ColorStateListItem); + + final float defaultAlphaMod; + if (themeAttrsList[i][R.styleable.ColorStateListItem_color] != 0) { + // If the base color hasn't been resolved yet, the current + // color's alpha channel is either full-opacity (if we + // haven't resolved the alpha modulation yet) or + // pre-modulated. Either is okay as a default value. + defaultAlphaMod = Color.alpha(mColors[i]) / 255.0f; + } else { + // Otherwise, the only correct default value is 1. Even if + // nothing is resolved during this call, we can apply this + // multiple times without losing of information. + defaultAlphaMod = 1.0f; + } + final int baseColor = a.getColor( R.styleable.ColorStateListItem_color, mColors[i]); final float alphaMod = a.getFloat( - R.styleable.ColorStateListItem_alpha, 1.0f); - + R.styleable.ColorStateListItem_alpha, defaultAlphaMod); mColors[i] = modulateColorAlpha(baseColor, alphaMod); + + // Account for any configuration changes. mChangingConfigurations |= a.getChangingConfigurations(); + // Extract the theme attributes, if any. themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]); if (themeAttrsList[i] != null) { hasUnresolvedAttrs = true; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 334d180..6e77e33 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -393,10 +393,11 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does not exist. * * @return String The string data associated with the resource, - * stripped of styled text information. + * stripped of styled text information. */ + @NonNull public String getString(@StringRes int id) throws NotFoundException { - CharSequence res = getText(id); + final CharSequence res = getText(id); if (res != null) { return res.toString(); } @@ -421,11 +422,11 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does not exist. * * @return String The string data associated with the resource, - * stripped of styled text information. + * stripped of styled text information. */ - public String getString(@StringRes int id, Object... formatArgs) - throws NotFoundException { - String raw = getString(id); + @NonNull + public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException { + final String raw = getString(id); return String.format(mConfiguration.locale, raw, formatArgs); } diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index adab9be..02793f1 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -182,6 +182,10 @@ public abstract class DisplayManagerInternal { // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter). public float screenAutoBrightnessAdjustment; + // Set to true if screenBrightness and screenAutoBrightnessAdjustment were both + // set by the user as opposed to being programmatically controlled by apps. + public boolean brightnessSetByUser; + // If true, enables automatic brightness control. public boolean useAutoBrightness; @@ -229,6 +233,7 @@ public abstract class DisplayManagerInternal { useProximitySensor = other.useProximitySensor; screenBrightness = other.screenBrightness; screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment; + brightnessSetByUser = other.brightnessSetByUser; useAutoBrightness = other.useAutoBrightness; blockScreenOn = other.blockScreenOn; lowPowerMode = other.lowPowerMode; @@ -249,6 +254,7 @@ public abstract class DisplayManagerInternal { && useProximitySensor == other.useProximitySensor && screenBrightness == other.screenBrightness && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment + && brightnessSetByUser == other.brightnessSetByUser && useAutoBrightness == other.useAutoBrightness && blockScreenOn == other.blockScreenOn && lowPowerMode == other.lowPowerMode @@ -268,6 +274,7 @@ public abstract class DisplayManagerInternal { + ", useProximitySensor=" + useProximitySensor + ", screenBrightness=" + screenBrightness + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment + + ", brightnessSetByUser=" + brightnessSetByUser + ", useAutoBrightness=" + useAutoBrightness + ", blockScreenOn=" + blockScreenOn + ", lowPowerMode=" + lowPowerMode diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 2257b0a..9f344ad 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -42,6 +42,7 @@ import java.util.HashMap; import java.util.List; import javax.crypto.Cipher; +import javax.crypto.Mac; /** * A class that coordinates access to the fingerprint hardware. @@ -195,18 +196,26 @@ public class FingerprintManager { /** * A wrapper class for the crypto objects supported by FingerprintManager. Currently the - * framework supports {@link Signature} and {@link Cipher} objects. + * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. */ public static class CryptoObject { - public CryptoObject(Signature signature) { + public CryptoObject(@NonNull Signature signature) { mSignature = signature; mCipher = null; + mMac = null; } - public CryptoObject(Cipher cipher) { + public CryptoObject(@NonNull Cipher cipher) { mCipher = cipher; mSignature = null; + mMac = null; + } + + public CryptoObject(@NonNull Mac mac) { + mMac = mac; + mCipher = null; + mSignature = null; } /** @@ -222,6 +231,12 @@ public class FingerprintManager { public Cipher getCipher() { return mCipher; } /** + * Get {@link Mac} object. + * @return {@link Mac} object or null if this doesn't contain one. + */ + public Mac getMac() { return mMac; } + + /** * @hide * @return the opId associated with this object or 0 if none */ @@ -230,12 +245,15 @@ public class FingerprintManager { return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature); } else if (mCipher != null) { return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher); + } else if (mMac != null) { + return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac); } return 0; } private final Signature mSignature; private final Cipher mCipher; + private final Mac mMac; }; /** diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 1a42319..410d550 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -45,6 +45,7 @@ public class UsbDevice implements Parcelable { private final String mName; private final String mManufacturerName; private final String mProductName; + private final String mVersion; private final String mSerialNumber; private final int mVendorId; private final int mProductId; @@ -62,7 +63,7 @@ public class UsbDevice implements Parcelable { */ public UsbDevice(String name, int vendorId, int productId, int Class, int subClass, int protocol, - String manufacturerName, String productName, String serialNumber) { + String manufacturerName, String productName, String version, String serialNumber) { mName = name; mVendorId = vendorId; mProductId = productId; @@ -71,6 +72,7 @@ public class UsbDevice implements Parcelable { mProtocol = protocol; mManufacturerName = manufacturerName; mProductName = productName; + mVersion = version; mSerialNumber = serialNumber; } @@ -104,6 +106,15 @@ public class UsbDevice implements Parcelable { } /** + * Returns the version number of the device. + * + * @return the device version + */ + public String getVersion() { + return mVersion; + } + + /** * Returns the serial number of the device. * * @return the serial number name @@ -263,7 +274,7 @@ public class UsbDevice implements Parcelable { ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + - ",mSerialNumber=" + mSerialNumber + ",mConfigurations=["); + ",mVersion=" + mVersion + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=["); for (int i = 0; i < mConfigurations.length; i++) { builder.append("\n"); builder.append(mConfigurations[i].toString()); @@ -283,10 +294,11 @@ public class UsbDevice implements Parcelable { int protocol = in.readInt(); String manufacturerName = in.readString(); String productName = in.readString(); + String version = in.readString(); String serialNumber = in.readString(); Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader()); UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, - manufacturerName, productName, serialNumber); + manufacturerName, productName, version, serialNumber); device.setConfigurations(configurations); return device; } @@ -309,6 +321,7 @@ public class UsbDevice implements Parcelable { parcel.writeInt(mProtocol); parcel.writeString(mManufacturerName); parcel.writeString(mProductName); + parcel.writeString(mVersion); parcel.writeString(mSerialNumber); parcel.writeParcelableArray(mConfigurations, 0); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index c722fbc..7f5f377 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -38,8 +38,6 @@ interface INetworkPolicyManager { boolean isUidForeground(int uid); - int[] getPowerSaveAppIdWhitelist(); - void registerListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index bc03637..ecc3fb4 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -41,6 +41,7 @@ import java.util.HashSet; */ public class NetworkPolicyManager { + /* POLICY_* are masks and can be ORed */ /** No specific network policy, use system default. */ public static final int POLICY_NONE = 0x0; /** Reject network usage on metered networks when application in background. */ @@ -48,10 +49,17 @@ public class NetworkPolicyManager { /** Allow network use (metered or not) in the background in battery save mode. */ public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2; + /* RULE_* are not masks and they must be exclusive */ /** All network traffic should be allowed. */ public static final int RULE_ALLOW_ALL = 0x0; /** Reject traffic on metered networks. */ public static final int RULE_REJECT_METERED = 0x1; + /** Reject traffic on all networks. */ + public static final int RULE_REJECT_ALL = 0x2; + + public static final int FIREWALL_RULE_DEFAULT = 0; + public static final int FIREWALL_RULE_ALLOW = 1; + public static final int FIREWALL_RULE_DENY = 2; private static final boolean ALLOW_PLATFORM_APP_POLICY = true; @@ -80,7 +88,7 @@ public class NetworkPolicyManager { * Set policy flags for specific UID. * * @param policy {@link #POLICY_NONE} or combination of flags like - * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}. + * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}. */ public void setUidPolicy(int uid, int policy) { try { @@ -129,14 +137,6 @@ public class NetworkPolicyManager { } } - public int[] getPowerSaveAppIdWhitelist() { - try { - return mService.getPowerSaveAppIdWhitelist(); - } catch (RemoteException e) { - return new int[0]; - } - } - public void registerListener(INetworkPolicyListener listener) { try { mService.registerListener(listener); @@ -330,6 +330,8 @@ public class NetworkPolicyManager { fout.write("["); if ((rules & RULE_REJECT_METERED) != 0) { fout.write("REJECT_METERED"); + } else if ((rules & RULE_REJECT_ALL) != 0) { + fout.write("REJECT_ALL"); } fout.write("]"); } diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index f305b2a..4a8dfbc 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -1657,7 +1657,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { /** * Searches the query string for the first value with the given key. * - * <p><strong>Warning:</strong> Prior to Ice Cream Sandwich, this decoded + * <p><strong>Warning:</strong> Prior to Jelly Bean, this decoded * the '+' character as '+' rather than ' '. * * @param key which will be encoded diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 2eb97f1..e3e16eb 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -758,7 +758,6 @@ public class Environment { * @hide */ public static File maybeTranslateEmulatedPathToInternal(File path) { - // TODO: bring back this optimization - return path; + return StorageManager.maybeTranslateEmulatedPathToInternal(path); } } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 931cd3e..021e5e4 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -390,7 +390,7 @@ public class FileUtils { * attacks. */ public static boolean contains(File dir, File file) { - if (file == null) return false; + if (dir == null || file == null) return false; String dirPath = dir.getAbsolutePath(); String filePath = file.getAbsolutePath(); diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl new file mode 100644 index 0000000..3cb29ff --- /dev/null +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -0,0 +1,26 @@ +/** + * 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.os; + +/** @hide */ +interface IDeviceIdleController { + void addPowerSaveWhitelistApp(String name); + void removePowerSaveWhitelistApp(String name); + String[] getSystemPowerWhitelist(); + String[] getFullPowerWhitelist(); + int[] getAppIdWhitelist(); +} diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index f93550a..b29e8d0 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -342,7 +342,7 @@ interface INetworkManagementService void setFirewallInterfaceRule(String iface, boolean allow); void setFirewallEgressSourceRule(String addr, boolean allow); void setFirewallEgressDestRule(String addr, int port, boolean allow); - void setFirewallUidRule(int uid, boolean allow); + void setFirewallUidRule(int uid, int rule); /** * Set all packets from users in ranges to go through VPN specified by netId. diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl index 73a68f1..0cc1603 100644 --- a/core/java/android/os/IPermissionController.aidl +++ b/core/java/android/os/IPermissionController.aidl @@ -20,4 +20,5 @@ package android.os; /** @hide */ interface IPermissionController { boolean checkPermission(String permission, int pid, int uid); + String[] getPackagesForUid(int uid); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 01c9a21..1d9d7d2 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -920,6 +920,14 @@ public final class PowerManager { = "android.os.action.DEVICE_IDLE_MODE_CHANGED"; /** + * @hide Intent that is broadcast when the set of power save whitelist apps has changed. + * This broadcast is only sent to registered receivers. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_SAVE_WHITELIST_CHANGED + = "android.os.action.POWER_SAVE_WHITELIST_CHANGED"; + + /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change. * This broadcast is only sent to registered receivers. * diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 16e0bf7..fcde3f4 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -942,6 +942,24 @@ public interface IMountService extends IInterface { } @Override + public VolumeRecord[] getVolumeRecords(int _flags) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + VolumeRecord[] _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(_flags); + mRemote.transact(Stub.TRANSACTION_getVolumeRecords, _data, _reply, 0); + _reply.readException(); + _result = _reply.createTypedArray(VolumeRecord.CREATOR); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + + @Override public void mount(String volId) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -1033,12 +1051,12 @@ public interface IMountService extends IInterface { } @Override - public void setVolumeNickname(String volId, String nickname) throws RemoteException { + public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(volId); + _data.writeString(fsUuid); _data.writeString(nickname); mRemote.transact(Stub.TRANSACTION_setVolumeNickname, _data, _reply, 0); _reply.readException(); @@ -1049,12 +1067,12 @@ public interface IMountService extends IInterface { } @Override - public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException { + public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(volId); + _data.writeString(fsUuid); _data.writeInt(flags); _data.writeInt(mask); mRemote.transact(Stub.TRANSACTION_setVolumeUserFlags, _data, _reply, 0); @@ -1066,6 +1084,21 @@ public interface IMountService extends IInterface { } @Override + public void forgetVolume(String fsUuid) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(fsUuid); + mRemote.transact(Stub.TRANSACTION_forgetVolume, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override public String getPrimaryStorageUuid() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -1192,20 +1225,22 @@ public interface IMountService extends IInterface { static final int TRANSACTION_getDisks = IBinder.FIRST_CALL_TRANSACTION + 44; static final int TRANSACTION_getVolumes = IBinder.FIRST_CALL_TRANSACTION + 45; + static final int TRANSACTION_getVolumeRecords = IBinder.FIRST_CALL_TRANSACTION + 46; - static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 46; - static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 47; - static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 48; + static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 47; + static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 48; + static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 49; - static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 49; - static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 50; - static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 51; + static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 50; + static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 51; + static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 52; - static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 52; - static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 53; + static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 53; + static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 54; + static final int TRANSACTION_forgetVolume = IBinder.FIRST_CALL_TRANSACTION + 55; - static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 54; - static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 55; + static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 56; + static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57; /** * Cast an IBinder object into an IMountService interface, generating a @@ -1647,6 +1682,14 @@ public interface IMountService extends IInterface { reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; } + case TRANSACTION_getVolumeRecords: { + data.enforceInterface(DESCRIPTOR); + int _flags = data.readInt(); + VolumeRecord[] volumes = getVolumeRecords(_flags); + reply.writeNoException(); + reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } case TRANSACTION_mount: { data.enforceInterface(DESCRIPTOR); String volId = data.readString(); @@ -1707,6 +1750,13 @@ public interface IMountService extends IInterface { reply.writeNoException(); return true; } + case TRANSACTION_forgetVolume: { + data.enforceInterface(DESCRIPTOR); + String fsUuid = data.readString(); + forgetVolume(fsUuid); + reply.writeNoException(); + return true; + } case TRANSACTION_getPrimaryStorageUuid: { data.enforceInterface(DESCRIPTOR); String volumeUuid = getPrimaryStorageUuid(); @@ -2012,6 +2062,7 @@ public interface IMountService extends IInterface { public DiskInfo[] getDisks() throws RemoteException; public VolumeInfo[] getVolumes(int flags) throws RemoteException; + public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException; public void mount(String volId) throws RemoteException; public void unmount(String volId) throws RemoteException; @@ -2021,8 +2072,9 @@ public interface IMountService extends IInterface { public void partitionPrivate(String diskId) throws RemoteException; public void partitionMixed(String diskId, int ratio) throws RemoteException; - public void setVolumeNickname(String volId, String nickname) throws RemoteException; - public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException; + public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException; + public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException; + public void forgetVolume(String fsUuid) throws RemoteException; public String getPrimaryStorageUuid() throws RemoteException; public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java index fcb4779..c958fb0 100644 --- a/core/java/android/os/storage/IMountServiceListener.java +++ b/core/java/android/os/storage/IMountServiceListener.java @@ -91,10 +91,17 @@ public interface IMountServiceListener extends IInterface { reply.writeNoException(); return true; } - case TRANSACTION_onVolumeMetadataChanged: { + case TRANSACTION_onVolumeRecordChanged: { data.enforceInterface(DESCRIPTOR); - final VolumeInfo vol = (VolumeInfo) data.readParcelable(null); - onVolumeMetadataChanged(vol); + final VolumeRecord rec = (VolumeRecord) data.readParcelable(null); + onVolumeRecordChanged(rec); + reply.writeNoException(); + return true; + } + case TRANSACTION_onVolumeForgotten: { + data.enforceInterface(DESCRIPTOR); + final String fsUuid = data.readString(); + onVolumeForgotten(fsUuid); reply.writeNoException(); return true; } @@ -192,13 +199,29 @@ public interface IMountServiceListener extends IInterface { } @Override - public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException { + public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); - _data.writeParcelable(vol, 0); - mRemote.transact(Stub.TRANSACTION_onVolumeMetadataChanged, _data, _reply, + _data.writeParcelable(rec, 0); + mRemote.transact(Stub.TRANSACTION_onVolumeRecordChanged, _data, _reply, + android.os.IBinder.FLAG_ONEWAY); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void onVolumeForgotten(String fsUuid) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(fsUuid); + mRemote.transact(Stub.TRANSACTION_onVolumeForgotten, _data, _reply, android.os.IBinder.FLAG_ONEWAY); _reply.readException(); } finally { @@ -228,8 +251,9 @@ public interface IMountServiceListener extends IInterface { static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_onVolumeStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 2); - static final int TRANSACTION_onVolumeMetadataChanged = (IBinder.FIRST_CALL_TRANSACTION + 3); - static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 4); + 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); } /** @@ -252,8 +276,8 @@ public interface IMountServiceListener extends IInterface { public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) throws RemoteException; - - public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException; + public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException; + public void onVolumeForgotten(String fsUuid) throws RemoteException; public void onDiskScanned(DiskInfo disk, int volumeCount) throws RemoteException; } diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java index 6a0140e..214c60d 100644 --- a/core/java/android/os/storage/StorageEventListener.java +++ b/core/java/android/os/storage/StorageEventListener.java @@ -41,7 +41,10 @@ public class StorageEventListener { public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { } - public void onVolumeMetadataChanged(VolumeInfo vol) { + public void onVolumeRecordChanged(VolumeRecord rec) { + } + + public void onVolumeForgotten(String fsUuid) { } public void onDiskScanned(DiskInfo disk, int volumeCount) { diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 6116aef..50e7d1c 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -34,6 +34,7 @@ import android.os.ServiceManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.SomeArgs; @@ -79,9 +80,6 @@ public class StorageManager { /** {@hide} */ public static final String UUID_PRIMARY_PHYSICAL = "primary_physical"; - /** {@hide} */ - public static final int FLAG_ALL_METADATA = 1 << 0; - private final Context mContext; private final ContentResolver mResolver; @@ -95,8 +93,9 @@ public class StorageManager { Handler.Callback { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; - private static final int MSG_VOLUME_METADATA_CHANGED = 3; - private static final int MSG_DISK_SCANNED = 4; + 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; final StorageEventListener mCallback; final Handler mHandler; @@ -119,8 +118,12 @@ public class StorageManager { mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); args.recycle(); return true; - case MSG_VOLUME_METADATA_CHANGED: - mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1); + case MSG_VOLUME_RECORD_CHANGED: + mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1); + args.recycle(); + return true; + case MSG_VOLUME_FORGOTTEN: + mCallback.onVolumeForgotten((String) args.arg1); args.recycle(); return true; case MSG_DISK_SCANNED: @@ -156,10 +159,17 @@ public class StorageManager { } @Override - public void onVolumeMetadataChanged(VolumeInfo vol) { + public void onVolumeRecordChanged(VolumeRecord rec) { final SomeArgs args = SomeArgs.obtain(); - args.arg1 = vol; - mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget(); + args.arg1 = rec; + mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); + } + + @Override + public void onVolumeForgotten(String fsUuid) { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = fsUuid; + mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); } @Override @@ -248,8 +258,9 @@ public class StorageManager { } /** {@hide} */ + @Deprecated public static StorageManager from(Context context) { - return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + return context.getSystemService(StorageManager.class); } /** @@ -516,6 +527,18 @@ public class StorageManager { } /** {@hide} */ + public @Nullable VolumeRecord findRecordByUuid(String fsUuid) { + Preconditions.checkNotNull(fsUuid); + // TODO; go directly to service to make this faster + for (VolumeRecord rec : getVolumeRecords()) { + if (Objects.equals(rec.fsUuid, fsUuid)) { + return rec; + } + } + return null; + } + + /** {@hide} */ public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) { return findVolumeById(emulatedVol.getId().replace("emulated", "private")); } @@ -526,14 +549,29 @@ public class StorageManager { } /** {@hide} */ + public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) { + if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { + return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); + } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { + return getPrimaryPhysicalVolume(); + } else { + return findVolumeByUuid(volumeUuid); + } + } + + /** {@hide} */ public @NonNull List<VolumeInfo> getVolumes() { - return getVolumes(0); + try { + return Arrays.asList(mMountService.getVolumes(0)); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } /** {@hide} */ - public @NonNull List<VolumeInfo> getVolumes(int flags) { + public @NonNull List<VolumeRecord> getVolumeRecords() { try { - return Arrays.asList(mMountService.getVolumes(flags)); + return Arrays.asList(mMountService.getVolumeRecords(0)); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -541,13 +579,25 @@ public class StorageManager { /** {@hide} */ public @Nullable String getBestVolumeDescription(VolumeInfo vol) { - String descrip = vol.getDescription(); - if (vol.disk != null) { - if (TextUtils.isEmpty(descrip)) { - descrip = vol.disk.getDescription(); + if (vol == null) return null; + + // Nickname always takes precedence when defined + if (!TextUtils.isEmpty(vol.fsUuid)) { + final VolumeRecord rec = findRecordByUuid(vol.fsUuid); + if (!TextUtils.isEmpty(rec.nickname)) { + return rec.nickname; } } - return descrip; + + if (!TextUtils.isEmpty(vol.getDescription())) { + return vol.getDescription(); + } + + if (vol.disk != null) { + return vol.disk.getDescription(); + } + + return null; } /** {@hide} */ @@ -616,29 +666,62 @@ public class StorageManager { } /** {@hide} */ - public void setVolumeNickname(String volId, String nickname) { + public void wipeAdoptableDisks() { + // We only wipe devices in "adoptable" locations, which are in a + // long-term stable slot/location on the device, where apps have a + // reasonable chance of storing sensitive data. (Apps need to go through + // SAF to write to transient volumes.) + final List<DiskInfo> disks = getDisks(); + for (DiskInfo disk : disks) { + final String diskId = disk.getId(); + if (disk.isAdoptable()) { + Slog.d(TAG, "Found adoptable " + diskId + "; wiping"); + try { + // TODO: switch to explicit wipe command when we have it, + // for now rely on the fact that vfat format does a wipe + mMountService.partitionPublic(diskId); + } catch (Exception e) { + Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e); + } + } else { + Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId()); + } + } + } + + /** {@hide} */ + public void setVolumeNickname(String fsUuid, String nickname) { try { - mMountService.setVolumeNickname(volId, nickname); + mMountService.setVolumeNickname(fsUuid, nickname); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } /** {@hide} */ - public void setVolumeInited(String volId, boolean inited) { + public void setVolumeInited(String fsUuid, boolean inited) { try { - mMountService.setVolumeUserFlags(volId, inited ? VolumeInfo.USER_FLAG_INITED : 0, - VolumeInfo.USER_FLAG_INITED); + mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0, + VolumeRecord.USER_FLAG_INITED); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } /** {@hide} */ - public void setVolumeSnoozed(String volId, boolean snoozed) { + public void setVolumeSnoozed(String fsUuid, boolean snoozed) { try { - mMountService.setVolumeUserFlags(volId, snoozed ? VolumeInfo.USER_FLAG_SNOOZED : 0, - VolumeInfo.USER_FLAG_SNOOZED); + mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0, + VolumeRecord.USER_FLAG_SNOOZED); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** {@hide} */ + public void forgetVolume(String fsUuid) { + try { + mMountService.forgetVolume(fsUuid); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -804,6 +887,27 @@ public class StorageManager { DEFAULT_FULL_THRESHOLD_BYTES); } + /** {@hide} */ + public static File maybeTranslateEmulatedPathToInternal(File path) { + final IMountService mountService = IMountService.Stub.asInterface( + ServiceManager.getService("mount")); + try { + final VolumeInfo[] vols = mountService.getVolumes(0); + for (VolumeInfo vol : vols) { + if ((vol.getType() == VolumeInfo.TYPE_EMULATED + || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) { + final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(), + vol.getInternalPath(), path); + if (internalPath != null) { + return internalPath; + } + } + } + } catch (RemoteException ignored) { + } + return path; + } + /// Consts to match the password types in cryptfs.h /** @hide */ public static final int CRYPT_TYPE_PASSWORD = 0; diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 4e9cfc7..2622ee0 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -78,9 +78,6 @@ public class VolumeInfo implements Parcelable { public static final int MOUNT_FLAG_PRIMARY = 1 << 0; public static final int MOUNT_FLAG_VISIBLE = 1 << 1; - public static final int USER_FLAG_INITED = 1 << 0; - public static final int USER_FLAG_SNOOZED = 1 << 1; - private static SparseArray<String> sStateToEnvironment = new SparseArray<>(); private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>(); @@ -132,11 +129,10 @@ public class VolumeInfo implements Parcelable { public String fsUuid; public String fsLabel; public String path; + public String internalPath; /** Framework state */ public final int mtpIndex; - public String nickname; - public int userFlags = 0; public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) { this.id = Preconditions.checkNotNull(id); @@ -160,9 +156,8 @@ public class VolumeInfo implements Parcelable { fsUuid = parcel.readString(); fsLabel = parcel.readString(); path = parcel.readString(); + internalPath = parcel.readString(); mtpIndex = parcel.readInt(); - nickname = parcel.readString(); - userFlags = parcel.readInt(); } public static @NonNull String getEnvironmentForState(int state) { @@ -210,10 +205,6 @@ public class VolumeInfo implements Parcelable { return fsUuid; } - public @Nullable String getNickname() { - return nickname; - } - public int getMountUserId() { return mountUserId; } @@ -221,8 +212,6 @@ public class VolumeInfo implements Parcelable { public @Nullable String getDescription() { if (ID_PRIVATE_INTERNAL.equals(id)) { return Resources.getSystem().getString(com.android.internal.R.string.storage_internal); - } else if (!TextUtils.isEmpty(nickname)) { - return nickname; } else if (!TextUtils.isEmpty(fsLabel)) { return fsLabel; } else { @@ -250,14 +239,6 @@ public class VolumeInfo implements Parcelable { return (mountFlags & MOUNT_FLAG_VISIBLE) != 0; } - public boolean isInited() { - return (userFlags & USER_FLAG_INITED) != 0; - } - - public boolean isSnoozed() { - return (userFlags & USER_FLAG_SNOOZED) != 0; - } - public boolean isVisibleToUser(int userId) { if (type == TYPE_PUBLIC && userId == this.mountUserId) { return isVisible(); @@ -269,7 +250,11 @@ public class VolumeInfo implements Parcelable { } public File getPath() { - return new File(path); + return (path != null) ? new File(path) : null; + } + + public File getInternalPath() { + return (internalPath != null) ? new File(internalPath) : null; } public File getPathForUser(int userId) { @@ -356,14 +341,11 @@ public class VolumeInfo implements Parcelable { final Uri uri; if (type == VolumeInfo.TYPE_PUBLIC) { uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid); - } else if (VolumeInfo.ID_EMULATED_INTERNAL.equals(id)) { + } else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) { uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, DOCUMENT_ROOT_PRIMARY_EMULATED); - } else if (type == VolumeInfo.TYPE_EMULATED) { - // TODO: build intent once supported - uri = null; } else { - throw new IllegalArgumentException(); + return null; } final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT); @@ -393,9 +375,8 @@ public class VolumeInfo implements Parcelable { pw.printPair("fsLabel", fsLabel); pw.println(); pw.printPair("path", path); + pw.printPair("internalPath", internalPath); pw.printPair("mtpIndex", mtpIndex); - pw.printPair("nickname", nickname); - pw.printPair("userFlags", DebugUtils.flagsToString(getClass(), "USER_FLAG_", userFlags)); pw.decreaseIndent(); pw.println(); } @@ -460,8 +441,7 @@ public class VolumeInfo implements Parcelable { parcel.writeString(fsUuid); parcel.writeString(fsLabel); parcel.writeString(path); + parcel.writeString(internalPath); parcel.writeInt(mtpIndex); - parcel.writeString(nickname); - parcel.writeInt(userFlags); } } diff --git a/core/java/android/os/storage/VolumeRecord.java b/core/java/android/os/storage/VolumeRecord.java new file mode 100644 index 0000000..096e2dd --- /dev/null +++ b/core/java/android/os/storage/VolumeRecord.java @@ -0,0 +1,139 @@ +/* + * 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.os.storage; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.DebugUtils; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; + +import java.util.Objects; + +/** + * Metadata for a storage volume which may not be currently present. + * + * @hide + */ +public class VolumeRecord implements Parcelable { + public static final String EXTRA_FS_UUID = + "android.os.storage.extra.FS_UUID"; + + public static final int USER_FLAG_INITED = 1 << 0; + public static final int USER_FLAG_SNOOZED = 1 << 1; + + public final int type; + public final String fsUuid; + public String nickname; + public int userFlags; + + public VolumeRecord(int type, String fsUuid) { + this.type = type; + this.fsUuid = Preconditions.checkNotNull(fsUuid); + } + + public VolumeRecord(Parcel parcel) { + type = parcel.readInt(); + fsUuid = parcel.readString(); + nickname = parcel.readString(); + userFlags = parcel.readInt(); + } + + public int getType() { + return type; + } + + public String getFsUuid() { + return fsUuid; + } + + public String getNickname() { + return nickname; + } + + public boolean isInited() { + return (userFlags & USER_FLAG_INITED) != 0; + } + + public boolean isSnoozed() { + return (userFlags & USER_FLAG_SNOOZED) != 0; + } + + public void dump(IndentingPrintWriter pw) { + pw.println("VolumeRecord:"); + pw.increaseIndent(); + pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type)); + pw.printPair("fsUuid", fsUuid); + pw.printPair("nickname", nickname); + pw.printPair("userFlags", + DebugUtils.flagsToString(VolumeRecord.class, "USER_FLAG_", userFlags)); + pw.decreaseIndent(); + pw.println(); + } + + @Override + public VolumeRecord clone() { + final Parcel temp = Parcel.obtain(); + try { + writeToParcel(temp, 0); + temp.setDataPosition(0); + return CREATOR.createFromParcel(temp); + } finally { + temp.recycle(); + } + } + + @Override + public boolean equals(Object o) { + if (o instanceof VolumeRecord) { + return Objects.equals(fsUuid, ((VolumeRecord) o).fsUuid); + } else { + return false; + } + } + + @Override + public int hashCode() { + return fsUuid.hashCode(); + } + + public static final Creator<VolumeRecord> CREATOR = new Creator<VolumeRecord>() { + @Override + public VolumeRecord createFromParcel(Parcel in) { + return new VolumeRecord(in); + } + + @Override + public VolumeRecord[] newArray(int size) { + return new VolumeRecord[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(type); + parcel.writeString(fsUuid); + parcel.writeString(nickname); + parcel.writeInt(userFlags); + } +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 00c851b..293cf6f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -919,6 +919,15 @@ public final class Settings { = "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS"; /** + * Activity Action: Show Zen Mode event rule configuration settings. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_ZEN_MODE_EVENT_RULE_SETTINGS + = "android.settings.ZEN_MODE_EVENT_RULE_SETTINGS"; + + /** * Activity Action: Show Zen Mode external rule configuration settings. * * @hide diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java index b3a3aad..03248e5 100644 --- a/core/java/android/security/keymaster/KeyCharacteristics.java +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -87,6 +87,28 @@ public class KeyCharacteristics implements Parcelable { return result; } + public Long getLong(int tag) { + if (hwEnforced.containsTag(tag)) { + return hwEnforced.getLong(tag, -1); + } else if (swEnforced.containsTag(tag)) { + return swEnforced.getLong(tag, -1); + } else { + return null; + } + } + + public long getLong(int tag, long defaultValue) { + Long result = getLong(tag); + return (result != null) ? result : defaultValue; + } + + public List<Long> getLongs(int tag) { + List<Long> result = new ArrayList<Long>(); + result.addAll(hwEnforced.getLongs(tag)); + result.addAll(swEnforced.getLongs(tag)); + return result; + } + public Date getDate(int tag) { Date result = hwEnforced.getDate(tag, null); if (result == null) { @@ -105,11 +127,11 @@ public class KeyCharacteristics implements Parcelable { } } - public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) { - if (keyCharacteristics.hwEnforced.containsTag(tag)) { - return keyCharacteristics.hwEnforced.getBoolean(tag, false); + public boolean getBoolean(int tag) { + if (hwEnforced.containsTag(tag)) { + return hwEnforced.getBoolean(tag, false); } else { - return keyCharacteristics.swEnforced.getBoolean(tag, false); + return swEnforced.getBoolean(tag, false); } } } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 40baf9c..d8834fe 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -194,6 +194,9 @@ public final class KeymasterDefs { public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50; public static final int KM_ERROR_MISSING_NONCE = -51; public static final int KM_ERROR_INVALID_NONCE = -52; + public static final int KM_ERROR_UNSUPPORTED_CHUNK_LENGTH = -53; + public static final int KM_ERROR_RESCOPABLE_KEY_NOT_USABLE = -54; + public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55; public static final int KM_ERROR_UNIMPLEMENTED = -100; public static final int KM_ERROR_VERSION_MISMATCH = -101; public static final int KM_ERROR_UNKNOWN_ERROR = -1000; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 14e947c..f09f4d2 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -62,7 +62,7 @@ public class ZenModeConfig implements Parcelable { Calendar.WEDNESDAY, Calendar.THURSDAY }; public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY }; - public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; + public static final int[] MINUTE_BUCKETS = generateMinuteBuckets(); private static final int SECONDS_MS = 1000; private static final int MINUTES_MS = 60 * SECONDS_MS; private static final int ZERO_VALUE_MS = 10 * SECONDS_MS; @@ -95,7 +95,7 @@ public class ZenModeConfig implements Parcelable { private static final String MANUAL_TAG = "manual"; private static final String AUTOMATIC_TAG = "automatic"; - private static final String RULE_ATT_ID = "id"; + private static final String RULE_ATT_ID = "ruleId"; private static final String RULE_ATT_ENABLED = "enabled"; private static final String RULE_ATT_SNOOZING = "snoozing"; private static final String RULE_ATT_NAME = "name"; @@ -201,6 +201,18 @@ public class ZenModeConfig implements Parcelable { } } + private static int[] generateMinuteBuckets() { + final int maxHrs = 12; + final int[] buckets = new int[maxHrs + 3]; + buckets[0] = 15; + buckets[1] = 30; + buckets[2] = 45; + for (int i = 1; i <= maxHrs; i++) { + buckets[2 + i] = 60 * i; + } + return buckets; + } + public static String sourceToString(int source) { switch (source) { case SOURCE_ANYONE: @@ -267,6 +279,15 @@ public class ZenModeConfig implements Parcelable { } } + private static long tryParseLong(String value, long defValue) { + if (TextUtils.isEmpty(value)) return defValue; + try { + return Long.valueOf(value); + } catch (NumberFormatException e) { + return defValue; + } + } + public static ZenModeConfig readXml(XmlPullParser parser, Migration migration) throws XmlPullParserException, IOException { int type = parser.getEventType(); @@ -298,10 +319,10 @@ public class ZenModeConfig implements Parcelable { throw new IndexOutOfBoundsException("bad source in config:" + rt.allowFrom); } } else if (MANUAL_TAG.equals(tag)) { - rt.manualRule = readRuleXml(parser); + rt.manualRule = readRuleXml(parser, false /*conditionRequired*/); } else if (AUTOMATIC_TAG.equals(tag)) { final String id = parser.getAttributeValue(null, RULE_ATT_ID); - final ZenRule automaticRule = readRuleXml(parser); + final ZenRule automaticRule = readRuleXml(parser, true /*conditionRequired*/); if (id != null && automaticRule != null) { rt.automaticRules.put(id, automaticRule); } @@ -341,7 +362,7 @@ public class ZenModeConfig implements Parcelable { out.endTag(null, ZEN_TAG); } - public static ZenRule readRuleXml(XmlPullParser parser) { + public static ZenRule readRuleXml(XmlPullParser parser, boolean conditionRequired) { final ZenRule rt = new ZenRule(); rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true); rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false); @@ -355,7 +376,7 @@ public class ZenModeConfig implements Parcelable { rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID); rt.component = safeComponentName(parser, RULE_ATT_COMPONENT); rt.condition = readConditionXml(parser); - return rt.condition != null ? rt : null; + return rt; } public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException { @@ -556,10 +577,12 @@ public class ZenModeConfig implements Parcelable { Condition.FLAG_RELEVANT_NOW); } - // For built-in conditions + // ==== Built-in system conditions ==== + public static final String SYSTEM_AUTHORITY = "android"; - // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951 + // ==== Built-in system condition: countdown ==== + public static final String COUNTDOWN_PATH = "countdown"; public static Uri toCountdownConditionId(long time) { @@ -586,9 +609,43 @@ public class ZenModeConfig implements Parcelable { return tryParseCountdownConditionId(conditionId) != 0; } - // built-in schedule conditions + // ==== Built-in system condition: schedule ==== + public static final String SCHEDULE_PATH = "schedule"; + public static Uri toScheduleConditionId(ScheduleInfo schedule) { + return new Uri.Builder().scheme(Condition.SCHEME) + .authority(SYSTEM_AUTHORITY) + .appendPath(SCHEDULE_PATH) + .appendQueryParameter("days", toDayList(schedule.days)) + .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute) + .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute) + .build(); + } + + public static boolean isValidScheduleConditionId(Uri conditionId) { + return tryParseScheduleConditionId(conditionId) != null; + } + + public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) { + final boolean isSchedule = conditionId != null + && conditionId.getScheme().equals(Condition.SCHEME) + && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY) + && conditionId.getPathSegments().size() == 1 + && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH); + if (!isSchedule) return null; + final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start")); + final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end")); + if (start == null || end == null) return null; + final ScheduleInfo rt = new ScheduleInfo(); + rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\."); + rt.startHour = start[0]; + rt.startMinute = start[1]; + rt.endHour = end[0]; + rt.endMinute = end[1]; + return rt; + } + public static class ScheduleInfo { public int[] days; public int startHour; @@ -626,39 +683,76 @@ public class ZenModeConfig implements Parcelable { } } - public static Uri toScheduleConditionId(ScheduleInfo schedule) { + // ==== Built-in system condition: event ==== + + public static final String EVENT_PATH = "event"; + + public static Uri toEventConditionId(EventInfo event) { return new Uri.Builder().scheme(Condition.SCHEME) .authority(SYSTEM_AUTHORITY) - .appendPath(SCHEDULE_PATH) - .appendQueryParameter("days", toDayList(schedule.days)) - .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute) - .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute) + .appendPath(EVENT_PATH) + .appendQueryParameter("calendar", Long.toString(event.calendar)) + .appendQueryParameter("attendance", Integer.toString(event.attendance)) + .appendQueryParameter("reply", Integer.toString(event.reply)) .build(); } - public static boolean isValidScheduleConditionId(Uri conditionId) { - return tryParseScheduleConditionId(conditionId) != null; + public static boolean isValidEventConditionId(Uri conditionId) { + return tryParseEventConditionId(conditionId) != null; } - public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) { - final boolean isSchedule = conditionId != null + public static EventInfo tryParseEventConditionId(Uri conditionId) { + final boolean isEvent = conditionId != null && conditionId.getScheme().equals(Condition.SCHEME) && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY) && conditionId.getPathSegments().size() == 1 - && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH); - if (!isSchedule) return null; - final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start")); - final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end")); - if (start == null || end == null) return null; - final ScheduleInfo rt = new ScheduleInfo(); - rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\."); - rt.startHour = start[0]; - rt.startMinute = start[1]; - rt.endHour = end[0]; - rt.endMinute = end[1]; + && conditionId.getPathSegments().get(0).equals(EVENT_PATH); + if (!isEvent) return null; + final EventInfo rt = new EventInfo(); + rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"), 0L); + rt.attendance = tryParseInt(conditionId.getQueryParameter("attendance"), 0); + rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0); return rt; } + public static class EventInfo { + public static final int ATTENDANCE_REQUIRED_OR_OPTIONAL = 0; + public static final int ATTENDANCE_REQUIRED = 1; + public static final int ATTENDANCE_OPTIONAL = 2; + + public static final int REPLY_ANY = 0; + public static final int REPLY_ANY_EXCEPT_NO = 1; + public static final int REPLY_YES = 2; + + public long calendar; // CalendarContract.Calendars._ID, or 0 for any + public int attendance; + public int reply; + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof EventInfo)) return false; + final EventInfo other = (EventInfo) o; + return calendar == other.calendar + && attendance == other.attendance + && reply == other.reply; + } + + public EventInfo copy() { + final EventInfo rt = new EventInfo(); + rt.calendar = calendar; + rt.attendance = attendance; + rt.reply = reply; + return rt; + } + } + + // ==== End built-in system conditions ==== + private static int[] tryParseHourAndMinute(String value) { if (TextUtils.isEmpty(value)) return null; final int i = value.indexOf('.'); diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index e991d84..ce94315 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -403,4 +403,12 @@ public class RecognizerIntent { */ public static final String EXTRA_SUPPORTED_LANGUAGES = "android.speech.extra.SUPPORTED_LANGUAGES"; + + /** + * Optional boolean, to be used with {@link #ACTION_RECOGNIZE_SPEECH}, + * {@link #ACTION_VOICE_SEARCH_HANDS_FREE}, {@link #ACTION_WEB_SEARCH} to indicate whether to + * only use an offline speech recognition engine. The default is false, meaning that either + * network or offline recognition engines may be used. + */ + public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE"; } diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index a7d9503..ca37d49 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -214,7 +214,7 @@ public class TransitionInflater { sConstructors.put(className, constructor); } } - + constructor.setAccessible(true); return constructor.newInstance(mContext, attrs); } } catch (InstantiationException e) { diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index aefced8..558b8f5 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -74,6 +74,7 @@ public class EventLog { private static final byte LONG_TYPE = 1; private static final byte STRING_TYPE = 2; private static final byte LIST_TYPE = 3; + private static final byte FLOAT_TYPE = 4; /** @param data containing event, read from the system */ /*package*/ Event(byte[] data) { @@ -106,7 +107,7 @@ public class EventLog { return mBuffer.getInt(offset); } - /** @return one of Integer, Long, String, null, or Object[] of same. */ + /** @return one of Integer, Long, Float, String, null, or Object[] of same. */ public synchronized Object getData() { try { int offset = mBuffer.getShort(HEADER_SIZE_OFFSET); @@ -130,10 +131,13 @@ public class EventLog { byte type = mBuffer.get(); switch (type) { case INT_TYPE: - return (Integer) mBuffer.getInt(); + return mBuffer.getInt(); case LONG_TYPE: - return (Long) mBuffer.getLong(); + return mBuffer.getLong(); + + case FLOAT_TYPE: + return mBuffer.getFloat(); case STRING_TYPE: try { @@ -180,6 +184,14 @@ public class EventLog { /** * Record an event log message. * @param tag The event type tag code + * @param value A value to log + * @return The number of bytes written + */ + public static native int writeEvent(int tag, float value); + + /** + * Record an event log message. + * @param tag The event type tag code * @param str A value to log * @return The number of bytes written */ diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index eedbc70..46dd857 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -234,25 +234,13 @@ public class DisplayListCanvas extends Canvas { * Draws the specified display list onto this canvas. The display list can only * be drawn if {@link android.view.RenderNode#isValid()} returns true. * - * @param renderNode The RenderNode to replay. + * @param renderNode The RenderNode to draw. */ public void drawRenderNode(RenderNode renderNode) { - drawRenderNode(renderNode, RenderNode.FLAG_CLIP_CHILDREN); + nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); } - /** - * Draws the specified display list onto this canvas. - * - * @param renderNode The RenderNode to replay. - * @param flags Optional flags about drawing, see {@link RenderNode} for - * the possible flags. - */ - public void drawRenderNode(RenderNode renderNode, int flags) { - nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList(), flags); - } - - private static native void nDrawRenderNode(long renderer, long renderNode, - int flags); + private static native void nDrawRenderNode(long renderer, long renderNode); /////////////////////////////////////////////////////////////////////////// // Hardware layer diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java index 794c8e7..a3e7a10 100644 --- a/core/java/android/view/PhoneWindow.java +++ b/core/java/android/view/PhoneWindow.java @@ -3599,7 +3599,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!mForcedNavigationBarColor) { mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000); } - if (a.getBoolean(R.styleable.Window_windowHasLightStatusBar, false)) { + if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) { decor.setSystemUiVisibility( decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index ad34f02..6db46e9 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -284,11 +284,6 @@ public class TextureView extends View { return LAYER_TYPE_HARDWARE; } - @Override - boolean hasStaticLayer() { - return true; - } - /** * Calling this method has no effect. */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 5ecda87..b5b7f0f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2592,7 +2592,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS * FLAG_TRANSLUCENT_STATUS}. * - * @see android.R.attr#windowHasLightStatusBar + * @see android.R.attr#windowLightStatusBar */ public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; @@ -14373,15 +14373,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Indicates whether this view has a static layer. A view with layer type - * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are - * dynamic. - */ - boolean hasStaticLayer() { - return true; - } - - /** * Indicates what type of layer is currently associated with this view. By default * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} @@ -15499,12 +15490,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (drawingWithRenderNode) { renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); } else if (layerType == LAYER_TYPE_NONE) { - int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; - if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0) { - layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; - } canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), - multipliedAlpha, layerFlags); + multipliedAlpha); } } else { // Alpha is handled by the child directly, clobber the layer's alpha @@ -15540,7 +15527,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; - ((DisplayListCanvas) canvas).drawRenderNode(renderNode, parentFlags); + ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { // Fast path for layouts with no backgrounds if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 4324e75..d0d4201 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3505,8 +3505,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final View[] children = mChildren; for (int i = 0; i < count; i++) { final View child = children[i]; - if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) && - child.hasStaticLayer()) { + if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) { recreateChildDisplayList(child); } } diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java index 478fa00..d271af2 100644 --- a/core/java/android/widget/DayPickerPagerAdapter.java +++ b/core/java/android/widget/DayPickerPagerAdapter.java @@ -286,14 +286,10 @@ class DayPickerPagerAdapter extends PagerAdapter { return null; } - private boolean isCalendarInRange(Calendar value) { - return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0; - } - private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { @Override public void onDayClick(SimpleMonthView view, Calendar day) { - if (day != null && isCalendarInRange(day)) { + if (day != null) { setSelectedDay(day); if (mOnDaySelectedListener != null) { diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java index 113e597..334afab 100644 --- a/core/java/android/widget/DayPickerView.java +++ b/core/java/android/widget/DayPickerView.java @@ -178,6 +178,13 @@ class DayPickerView extends ViewGroup { }); } + private void updateButtonVisibility(int position) { + final boolean hasPrev = position > 0; + final boolean hasNext = position < (mAdapter.getCount() - 1); + mPrevButton.setVisibility(hasPrev ? View.VISIBLE : View.INVISIBLE); + mNextButton.setVisibility(hasNext ? View.VISIBLE : View.INVISIBLE); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final ViewPager viewPager = mViewPager; @@ -218,12 +225,6 @@ class DayPickerView extends ViewGroup { final int height = bottom - top; mViewPager.layout(0, 0, width, height); - if (mViewPager.getChildCount() < 1) { - leftButton.setVisibility(View.INVISIBLE); - rightButton.setVisibility(View.INVISIBLE); - return; - } - final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0); final int monthHeight = monthView.getMonthHeight(); final int cellWidth = monthView.getCellWidth(); @@ -235,7 +236,6 @@ class DayPickerView extends ViewGroup { final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2; final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2; leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH); - leftButton.setVisibility(View.VISIBLE); final int rightDW = rightButton.getMeasuredWidth(); final int rightDH = rightButton.getMeasuredHeight(); @@ -243,7 +243,6 @@ class DayPickerView extends ViewGroup { final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2; rightButton.layout(rightIconRight - rightDW, rightIconTop, rightIconRight, rightIconTop + rightDH); - rightButton.setVisibility(View.VISIBLE); } public void setDayOfWeekTextAppearance(int resId) { @@ -399,10 +398,7 @@ class DayPickerView extends ViewGroup { @Override public void onPageSelected(int position) { - mPrevButton.setVisibility( - position > 0 ? View.VISIBLE : View.INVISIBLE); - mNextButton.setVisibility( - position < (mAdapter.getCount() - 1) ? View.VISIBLE : View.INVISIBLE); + updateButtonVisibility(position); } }; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 39b9907..35e7389 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -62,7 +62,6 @@ import android.text.TextUtils; import android.text.method.KeyListener; import android.text.method.MetaKeyKeyListener; import android.text.method.MovementMethod; -import android.text.method.PasswordTransformationMethod; import android.text.method.WordIterator; import android.text.style.EasyEditSpan; import android.text.style.SuggestionRangeSpan; @@ -145,16 +144,16 @@ public class Editor { InputContentType mInputContentType; InputMethodState mInputMethodState; - private static class TextDisplayList { - RenderNode displayList; + private static class TextRenderNode { + RenderNode renderNode; boolean isDirty; - public TextDisplayList(String name) { + public TextRenderNode(String name) { isDirty = true; - displayList = RenderNode.create(name, null); + renderNode = RenderNode.create(name, null); } - boolean needsRecord() { return isDirty || !displayList.isValid(); } + boolean needsRecord() { return isDirty || !renderNode.isValid(); } } - TextDisplayList[] mTextDisplayLists; + TextRenderNode[] mTextRenderNodes; boolean mFrozenWithFocus; boolean mSelectionMoved; @@ -360,10 +359,10 @@ public class Editor { } private void destroyDisplayListsData() { - if (mTextDisplayLists != null) { - for (int i = 0; i < mTextDisplayLists.length; i++) { - RenderNode displayList = mTextDisplayLists[i] != null - ? mTextDisplayLists[i].displayList : null; + if (mTextRenderNodes != null) { + for (int i = 0; i < mTextRenderNodes.length; i++) { + RenderNode displayList = mTextRenderNodes[i] != null + ? mTextRenderNodes[i].renderNode : null; if (displayList != null && displayList.isValid()) { displayList.destroyDisplayListData(); } @@ -682,34 +681,6 @@ public class Editor { } } - /** - * Unlike {@link TextView#textCanBeSelected()}, this method is based on the <i>current</i> state - * of the TextView. textCanBeSelected() has to be true (this is one of the conditions to have - * a selection controller (see {@link #prepareCursorControllers()}), but this is not sufficient. - */ - private boolean canSelectText() { - return hasSelectionController() && mTextView.getText().length() != 0; - } - - /** - * It would be better to rely on the input type for everything. A password inputType should have - * a password transformation. We should hence use isPasswordInputType instead of this method. - * - * We should: - * - Call setInputType in setKeyListener instead of changing the input type directly (which - * would install the correct transformation). - * - Refuse the installation of a non-password transformation in setTransformation if the input - * type is password. - * - * However, this is like this for legacy reasons and we cannot break existing apps. This method - * is useful since it matches what the user can see (obfuscated text or not). - * - * @return true if the current transformation method is of the password type. - */ - private boolean hasPasswordTransformationMethod() { - return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod; - } - private int getWordStart(int offset) { // FIXME - For this and similar methods we're not doing anything to check if there's // a LocaleSpan in the text, this may be something we should try handling or checking for. @@ -758,11 +729,11 @@ public class Editor { * successfully performed. */ private boolean selectCurrentWord() { - if (!canSelectText()) { + if (!mTextView.canSelectText()) { return false; } - if (hasPasswordTransformationMethod()) { + if (mTextView.hasPasswordTransformationMethod()) { // Always select all on a password field. // Cut/copy menu entries are not available for passwords, but being able to select all // is however useful to delete or paste to replace the entire content. @@ -1467,8 +1438,8 @@ public class Editor { firstLine, lastLine); if (layout instanceof DynamicLayout) { - if (mTextDisplayLists == null) { - mTextDisplayLists = ArrayUtils.emptyArray(TextDisplayList.class); + if (mTextRenderNodes == null) { + mTextRenderNodes = ArrayUtils.emptyArray(TextRenderNode.class); } DynamicLayout dynamicLayout = (DynamicLayout) layout; @@ -1489,19 +1460,19 @@ public class Editor { searchStartIndex); // Note how dynamic layout's internal block indices get updated from Editor blockIndices[i] = blockIndex; - if (mTextDisplayLists[blockIndex] != null) { - mTextDisplayLists[blockIndex].isDirty = true; + if (mTextRenderNodes[blockIndex] != null) { + mTextRenderNodes[blockIndex].isDirty = true; } searchStartIndex = blockIndex + 1; } - if (mTextDisplayLists[blockIndex] == null) { - mTextDisplayLists[blockIndex] = - new TextDisplayList("Text " + blockIndex); + if (mTextRenderNodes[blockIndex] == null) { + mTextRenderNodes[blockIndex] = + new TextRenderNode("Text " + blockIndex); } - final boolean blockDisplayListIsInvalid = mTextDisplayLists[blockIndex].needsRecord(); - RenderNode blockDisplayList = mTextDisplayLists[blockIndex].displayList; + final boolean blockDisplayListIsInvalid = mTextRenderNodes[blockIndex].needsRecord(); + RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode; if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) { final int blockBeginLine = endOfPreviousBlock + 1; final int top = layout.getLineTop(blockBeginLine); @@ -1528,7 +1499,7 @@ public class Editor { // brings this range of text back to the top left corner of the viewport displayListCanvas.translate(-left, -top); layout.drawText(displayListCanvas, blockBeginLine, blockEndLine); - mTextDisplayLists[blockIndex].isDirty = false; + mTextRenderNodes[blockIndex].isDirty = false; // No need to untranslate, previous context is popped after // drawDisplayList } finally { @@ -1543,8 +1514,7 @@ public class Editor { blockDisplayList.setLeftTopRightBottom(left, top, right, bottom); } - ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList, - 0 /* no child clipping, our TextView parent enforces it */); + ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList); endOfPreviousBlock = blockEndLine; } @@ -1558,7 +1528,7 @@ public class Editor { private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks, int searchStartIndex) { - int length = mTextDisplayLists.length; + int length = mTextRenderNodes.length; for (int i = searchStartIndex; i < length; i++) { boolean blockIndexFound = false; for (int j = 0; j < numberOfBlocks; j++) { @@ -1572,7 +1542,7 @@ public class Editor { } // No available index found, the pool has to grow - mTextDisplayLists = GrowingArrayUtils.append(mTextDisplayLists, length, null); + mTextRenderNodes = GrowingArrayUtils.append(mTextRenderNodes, length, null); return length; } @@ -1589,7 +1559,7 @@ public class Editor { * Invalidates all the sub-display lists that overlap the specified character range */ void invalidateTextDisplayList(Layout layout, int start, int end) { - if (mTextDisplayLists != null && layout instanceof DynamicLayout) { + if (mTextRenderNodes != null && layout instanceof DynamicLayout) { final int firstLine = layout.getLineForOffset(start); final int lastLine = layout.getLineForOffset(end); @@ -1609,7 +1579,7 @@ public class Editor { while (i < numberOfBlocks) { final int blockIndex = blockIndices[i]; if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) { - mTextDisplayLists[blockIndex].isDirty = true; + mTextRenderNodes[blockIndex].isDirty = true; } if (blockEndLines[i] >= lastLine) break; i++; @@ -1618,9 +1588,9 @@ public class Editor { } void invalidateTextDisplayList() { - if (mTextDisplayLists != null) { - for (int i = 0; i < mTextDisplayLists.length; i++) { - if (mTextDisplayLists[i] != null) mTextDisplayLists[i].isDirty = true; + if (mTextRenderNodes != null) { + for (int i = 0; i < mTextRenderNodes.length; i++) { + if (mTextRenderNodes[i] != null) mTextRenderNodes[i].isDirty = true; } } } @@ -1718,7 +1688,7 @@ public class Editor { return false; } - if (!canSelectText() || !mTextView.requestFocus()) { + if (!mTextView.canSelectText() || !mTextView.requestFocus()) { Log.w(TextView.LOG_TAG, "TextView does not support text selection. Action mode cancelled."); return false; @@ -3090,7 +3060,7 @@ public class Editor { MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } - if (canSelectText() && !hasPasswordTransformationMethod()) { + if (mTextView.canSelectAllText()) { menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll). setAlphabeticShortcut('a'). setShowAsAction( @@ -3847,6 +3817,10 @@ public class Editor { startSelectionActionModeWithoutSelection(); } } + } else { + if (mSelectionActionMode != null) { + mSelectionActionMode.invalidateContentRect(); + } } hideAfterDelay(); break; @@ -4491,7 +4465,7 @@ public class Editor { private class CorrectionHighlighter { private final Path mPath = new Path(); - private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mPaint = new Paint(); private int mStart, mEnd; private long mFadingStartTime; private RectF mTempRectF; diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index bbf120a..088adbb 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -18,6 +18,7 @@ package android.widget; import static android.widget.SuggestionsAdapter.getColumnString; +import android.annotation.Nullable; import android.app.PendingIntent; import android.app.SearchManager; import android.app.SearchableInfo; @@ -120,6 +121,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { private final Intent mVoiceWebSearchIntent; private final Intent mVoiceAppSearchIntent; + private final CharSequence mDefaultQueryHint; + private OnQueryTextListener mOnQueryChangeListener; private OnCloseListener mOnCloseListener; private OnFocusChangeListener mOnQueryTextFocusChangeListener; @@ -329,10 +332,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { setMaxWidth(maxWidth); } - final CharSequence queryHint = a.getText(R.styleable.SearchView_queryHint); - if (!TextUtils.isEmpty(queryHint)) { - setQueryHint(queryHint); - } + mDefaultQueryHint = a.getText(R.styleable.SearchView_defaultQueryHint); + mQueryHint = a.getText(R.styleable.SearchView_queryHint); final int imeOptions = a.getInt(R.styleable.SearchView_imeOptions, -1); if (imeOptions != -1) { @@ -570,36 +571,48 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } /** - * Sets the hint text to display in the query text field. This overrides any hint specified - * in the SearchableInfo. - * - * @param hint the hint text to display + * Sets the hint text to display in the query text field. This overrides + * any hint specified in the {@link SearchableInfo}. + * <p> + * This value may be specified as an empty string to prevent any query hint + * from being displayed. * + * @param hint the hint text to display or {@code null} to clear * @attr ref android.R.styleable#SearchView_queryHint */ - public void setQueryHint(CharSequence hint) { + public void setQueryHint(@Nullable CharSequence hint) { mQueryHint = hint; updateQueryHint(); } /** - * Gets the hint text to display in the query text field. - * @return the query hint text, if specified, null otherwise. + * Returns the hint text that will be displayed in the query text field. + * <p> + * The displayed query hint is chosen in the following order: + * <ol> + * <li>Non-null value set with {@link #setQueryHint(CharSequence)} + * <li>Value specified in XML using + * {@link android.R.styleable#SearchView_queryHint android:queryHint} + * <li>Valid string resource ID exposed by the {@link SearchableInfo} via + * {@link SearchableInfo#getHintId()} + * <li>Default hint provided by the theme against which the view was + * inflated + * </ol> * + * @return the displayed query hint text, or {@code null} if none set * @attr ref android.R.styleable#SearchView_queryHint */ + @Nullable public CharSequence getQueryHint() { + final CharSequence hint; if (mQueryHint != null) { - return mQueryHint; - } else if (mSearchable != null) { - CharSequence hint = null; - int hintId = mSearchable.getHintId(); - if (hintId != 0) { - hint = getContext().getString(hintId); - } - return hint; + hint = mQueryHint; + } else if (mSearchable != null && mSearchable.getHintId() != 0) { + hint = getContext().getText(mSearchable.getHintId()); + } else { + hint = mDefaultQueryHint; } - return null; + return hint; } /** @@ -1113,20 +1126,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } private void updateQueryHint() { - if (mQueryHint != null) { - mSearchSrcTextView.setHint(getDecoratedHint(mQueryHint)); - } else if (mSearchable != null) { - CharSequence hint = null; - int hintId = mSearchable.getHintId(); - if (hintId != 0) { - hint = getContext().getString(hintId); - } - if (hint != null) { - mSearchSrcTextView.setHint(getDecoratedHint(hint)); - } - } else { - mSearchSrcTextView.setHint(getDecoratedHint("")); - } + final CharSequence hint = getQueryHint(); + mSearchSrcTextView.setHint(getDecoratedHint(hint == null ? "" : hint)); } /** diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index 2778f0f..acf1df9 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -31,6 +31,7 @@ import android.text.TextPaint; import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.IntArray; +import android.util.MathUtils; import android.util.StateSet; import android.view.MotionEvent; import android.view.View; @@ -422,7 +423,8 @@ class SimpleMonthView extends View { int stateMask = 0; - if (day >= mEnabledDayStart && day <= mEnabledDayEnd) { + final boolean isDayEnabled = isDayEnabled(day); + if (isDayEnabled) { stateMask |= StateSet.VIEW_STATE_ENABLED; } @@ -435,8 +437,11 @@ class SimpleMonthView extends View { } else if (mTouchedItem == day) { stateMask |= StateSet.VIEW_STATE_PRESSED; - // Adjust the circle to be centered on the row. - canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDayHighlightPaint); + if (isDayEnabled) { + // Adjust the circle to be centered on the row. + canvas.drawCircle(colCenterRtl, rowCenter, + mDaySelectorRadius, mDayHighlightPaint); + } } final boolean isDayToday = mToday == day; @@ -460,6 +465,14 @@ class SimpleMonthView extends View { } } + private boolean isDayEnabled(int day) { + return day >= mEnabledDayStart && day <= mEnabledDayEnd; + } + + private boolean isValidDayOfMonth(int day) { + return day >= 1 && day <= mDaysInMonth; + } + private static boolean isValidDayOfWeek(int day) { return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY; } @@ -536,13 +549,6 @@ class SimpleMonthView extends View { mWeekStart = mCalendar.getFirstDayOfWeek(); } - if (enabledDayStart > 0 && enabledDayEnd < 32) { - mEnabledDayStart = enabledDayStart; - } - if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) { - mEnabledDayEnd = enabledDayEnd; - } - // Figure out what day today is. final Calendar today = Calendar.getInstance(); mToday = -1; @@ -554,6 +560,9 @@ class SimpleMonthView extends View { } } + mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth); + mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth); + // Invalidate the old title. mTitle = null; @@ -694,7 +703,7 @@ class SimpleMonthView extends View { final int col = (paddedXRtl * DAYS_IN_WEEK) / mPaddedWidth; final int index = col + row * DAYS_IN_WEEK; final int day = index + 1 - findDayOffset(); - if (day < 1 || day > mDaysInMonth) { + if (!isValidDayOfMonth(day)) { return -1; } @@ -708,7 +717,7 @@ class SimpleMonthView extends View { * @param outBounds the rect to populate with bounds */ private boolean getBoundsForDay(int id, Rect outBounds) { - if (id < 1 || id > mDaysInMonth) { + if (!isValidDayOfMonth(id)) { return false; } @@ -742,7 +751,7 @@ class SimpleMonthView extends View { * @param day the day that was clicked */ private boolean onDayClicked(int day) { - if (day < 0 || day > mDaysInMonth) { + if (!isValidDayOfMonth(day) || !isDayEnabled(day)) { return false; } @@ -774,7 +783,7 @@ class SimpleMonthView extends View { @Override protected int getVirtualViewAt(float x, float y) { final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f)); - if (day >= 0) { + if (day != -1) { return day; } return ExploreByTouchHelper.INVALID_ID; @@ -808,7 +817,13 @@ class SimpleMonthView extends View { node.setText(getDayText(virtualViewId)); node.setContentDescription(getDayDescription(virtualViewId)); node.setBoundsInParent(mTempRect); - node.addAction(AccessibilityAction.ACTION_CLICK); + + final boolean isDayEnabled = isDayEnabled(virtualViewId); + if (isDayEnabled) { + node.addAction(AccessibilityAction.ACTION_CLICK); + } + + node.setEnabled(isDayEnabled); if (virtualViewId == mActivatedDay) { // TODO: This should use activated once that's supported. @@ -835,7 +850,7 @@ class SimpleMonthView extends View { * @return a description of the virtual view */ private CharSequence getDayDescription(int id) { - if (id >= 1 && id <= mDaysInMonth) { + if (isValidDayOfMonth(id)) { mTempCalendar.set(mYear, mMonth, id); return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis()); } @@ -850,7 +865,7 @@ class SimpleMonthView extends View { * @return the visible text of the virtual view */ private CharSequence getDayText(int id) { - if (id >= 1 && id <= mDaysInMonth) { + if (isValidDayOfMonth(id)) { return Integer.toString(id); } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index ae779fe..f94f97c 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -216,7 +216,7 @@ public class Switch extends CompoundButton { public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + mTextPaint = new TextPaint(); final Resources res = getResources(); mTextPaint.density = res.getDisplayMetrics().density; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3e8df08..774a864 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -668,11 +668,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final Resources res = getResources(); final CompatibilityInfo compat = res.getCompatibilityInfo(); - mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + mTextPaint = new TextPaint(); mTextPaint.density = res.getDisplayMetrics().density; mTextPaint.setCompatibilityScaling(compat.applicationScale); - mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mHighlightPaint = new Paint(); mHighlightPaint.setCompatibilityScaling(compat.applicationScale); mMovement = getDefaultMovementMethod(); @@ -4569,7 +4569,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @return true if the current transformation method is of the password type. */ - private boolean hasPasswordTransformationMethod() { + boolean hasPasswordTransformationMethod() { return mTransformation instanceof PasswordTransformationMethod; } @@ -8583,7 +8583,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * a selection controller (see {@link Editor#prepareCursorControllers()}), but this is not * sufficient. */ - private boolean canSelectText() { + boolean canSelectText() { return mText.length() != 0 && mEditor != null && mEditor.hasSelectionController(); } @@ -9199,6 +9199,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } + boolean canSelectAllText() { + return canSelectText() && !hasPasswordTransformationMethod(); + } + boolean selectAllText() { // Need to hide insert point cursor controller before settings selection, otherwise insert // point cursor controller obtains cursor update event and update cursor with cancelling diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 2b77b2c..e347faa 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -405,8 +405,10 @@ public class ChooserActivity extends ResolverActivity { int launchedFromUid, boolean filterLastUsed, ChooserTarget[] callerChooserTargets) { super(context, initialIntents, rList, launchedFromUid, filterLastUsed); - for (ChooserTarget target : callerChooserTargets) { - mCallerTargets.add(new ChooserTargetInfo(target)); + if (callerChooserTargets != null) { + for (ChooserTarget target : callerChooserTargets) { + mCallerTargets.add(new ChooserTargetInfo(target)); + } } } diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index eff44bd..481ab0e 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -44,7 +44,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); - sPackageFilt.addAction(Intent.ACTION_UID_REMOVED); sPackageFilt.addDataScheme("package"); sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 092c148..3f96174 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -26,11 +26,12 @@ import android.os.Build; */ public class MetricsLogger implements MetricsConstants { // These constants are temporary, they should migrate to MetricsConstants. - // next value is 146; + // next value is 148; public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144; public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145; public static final int ACTION_BAN_APP_NOTES = 146; + public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 147; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java index 1a7fa0b..8ed5b5a 100644 --- a/core/java/com/android/internal/midi/MidiFramer.java +++ b/core/java/com/android/internal/midi/MidiFramer.java @@ -78,7 +78,7 @@ public class MidiFramer extends MidiReceiver { // Log.i(TAG, "SysEx End"); if (mInSysEx) { mReceiver.sendWithTimestamp(data, sysExStartOffset, - offset - sysExStartOffset, timestamp); + offset - sysExStartOffset + 1, timestamp); mInSysEx = false; sysExStartOffset = -1; } @@ -90,6 +90,11 @@ public class MidiFramer extends MidiReceiver { } } else { // real-time? // Single byte message interleaved with other data. + if (mInSysEx) { + mReceiver.sendWithTimestamp(data, sysExStartOffset, + offset - sysExStartOffset, timestamp); + sysExStartOffset = offset + 1; + } mReceiver.sendWithTimestamp(data, offset, 1, timestamp); } } else { // data byte @@ -110,7 +115,7 @@ public class MidiFramer extends MidiReceiver { } // send any accumulatedSysEx data - if (sysExStartOffset >= 0) { + if (sysExStartOffset >= 0 && sysExStartOffset < offset) { mReceiver.sendWithTimestamp(data, sysExStartOffset, offset - sysExStartOffset, timestamp); } diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java index 7d56e9e..a0d0b20 100644 --- a/core/java/com/android/internal/util/ImageUtils.java +++ b/core/java/com/android/internal/util/ImageUtils.java @@ -66,7 +66,7 @@ public class ImageUtils { COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888 ); mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap); - mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTempCompactBitmapPaint = new Paint(); mTempCompactBitmapPaint.setFilterBitmap(true); } mTempMatrix.reset(); diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 3a1e0ca..3f7696f 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -438,6 +438,9 @@ public final class FloatingToolbar { // Make sure a panel is set as the content. if (mContentContainer.getChildCount() == 0) { setMainPanelAsContent(); + // If we're yet to show the popup, set the container visibility to zero. + // The "show" animation will make this visible. + mContentContainer.setAlpha(0); } preparePopupContent(); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y); @@ -478,7 +481,7 @@ public final class FloatingToolbar { * Returns {@code true} if this popup is currently showing. {@code false} otherwise. */ public boolean isShowing() { - return mPopupWindow.isShowing() && !mDismissed && !mHidden; + return !mDismissed && !mHidden; } /** @@ -494,7 +497,7 @@ public final class FloatingToolbar { * This is a no-op if this popup is not showing. */ public void updateCoordinates(int x, int y) { - if (!isShowing()) { + if (!isShowing() || !mPopupWindow.isShowing()) { return; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 1096e34..3d23986 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -17,9 +17,11 @@ package com.android.internal.widget; import android.Manifest; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; +import android.bluetooth.BluetoothClass; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -142,11 +144,6 @@ public class LockPatternUtils { private DevicePolicyManager mDevicePolicyManager; private ILockSettings mLockSettingsService; - private final boolean mMultiUserMode; - - // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils. - private static volatile int sCurrentUserId = UserHandle.USER_NULL; - public DevicePolicyManager getDevicePolicyManager() { if (mDevicePolicyManager == null) { mDevicePolicyManager = @@ -171,12 +168,6 @@ public class LockPatternUtils { public LockPatternUtils(Context context) { mContext = context; mContentResolver = context.getContentResolver(); - - // If this is being called by the system or by an application like keyguard that - // has permision INTERACT_ACROSS_USERS, then LockPatternUtils will operate in multi-user - // mode where calls are for the current user rather than the user of the calling process. - mMultiUserMode = context.checkCallingOrSelfPermission( - Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PackageManager.PERMISSION_GRANTED; } private ILockSettings getLockSettings() { @@ -188,93 +179,55 @@ public class LockPatternUtils { return mLockSettingsService; } - public int getRequestedMinimumPasswordLength() { - return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId()); + public int getRequestedMinimumPasswordLength(int userId) { + return getDevicePolicyManager().getPasswordMinimumLength(null, userId); } /** * Gets the device policy password mode. If the mode is non-specific, returns * MODE_PATTERN which allows the user to choose anything. */ - public int getRequestedPasswordQuality() { - return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId()); - } - - public int getRequestedPasswordHistoryLength() { - return getRequestedPasswordHistoryLength(getCurrentOrCallingUserId()); + public int getRequestedPasswordQuality(int userId) { + return getDevicePolicyManager().getPasswordQuality(null, userId); } private int getRequestedPasswordHistoryLength(int userId) { return getDevicePolicyManager().getPasswordHistoryLength(null, userId); } - public int getRequestedPasswordMinimumLetters() { - return getDevicePolicyManager().getPasswordMinimumLetters(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumLetters(int userId) { + return getDevicePolicyManager().getPasswordMinimumLetters(null, userId); } - public int getRequestedPasswordMinimumUpperCase() { - return getDevicePolicyManager().getPasswordMinimumUpperCase(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumUpperCase(int userId) { + return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId); } - public int getRequestedPasswordMinimumLowerCase() { - return getDevicePolicyManager().getPasswordMinimumLowerCase(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumLowerCase(int userId) { + return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId); } - public int getRequestedPasswordMinimumNumeric() { - return getDevicePolicyManager().getPasswordMinimumNumeric(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumNumeric(int userId) { + return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId); } - public int getRequestedPasswordMinimumSymbols() { - return getDevicePolicyManager().getPasswordMinimumSymbols(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumSymbols(int userId) { + return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId); } - public int getRequestedPasswordMinimumNonLetter() { - return getDevicePolicyManager().getPasswordMinimumNonLetter(null, - getCurrentOrCallingUserId()); + public int getRequestedPasswordMinimumNonLetter(int userId) { + return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId); } - public void reportFailedPasswordAttempt() { - int userId = getCurrentOrCallingUserId(); + public void reportFailedPasswordAttempt(int userId) { getDevicePolicyManager().reportFailedPasswordAttempt(userId); getTrustManager().reportUnlockAttempt(false /* authenticated */, userId); getTrustManager().reportRequireCredentialEntry(userId); } - public void reportSuccessfulPasswordAttempt() { - getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId()); - getTrustManager().reportUnlockAttempt(true /* authenticated */, - getCurrentOrCallingUserId()); - } - - public void setCurrentUser(int userId) { - sCurrentUserId = userId; - } - - public int getCurrentUser() { - if (sCurrentUserId != UserHandle.USER_NULL) { - // Someone is regularly updating using setCurrentUser() use that value. - return sCurrentUserId; - } - try { - return ActivityManagerNative.getDefault().getCurrentUser().id; - } catch (RemoteException re) { - return UserHandle.USER_OWNER; - } - } - - private int getCurrentOrCallingUserId() { - if (mMultiUserMode) { - // TODO: This is a little inefficient. See if all users of this are able to - // handle USER_CURRENT and pass that instead. - return getCurrentUser(); - } else { - return UserHandle.getCallingUserId(); - } + public void reportSuccessfulPasswordAttempt(int userId) { + getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId); + getTrustManager().reportUnlockAttempt(true /* authenticated */, userId); } /** @@ -286,8 +239,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the pattern * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge) { - final int userId = getCurrentOrCallingUserId(); + public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) { try { return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId); } catch (RemoteException re) { @@ -301,8 +253,7 @@ public class LockPatternUtils { * @param pattern The pattern to check. * @return Whether the pattern matches the stored one. */ - public boolean checkPattern(List<LockPatternView.Cell> pattern) { - final int userId = getCurrentOrCallingUserId(); + public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) { try { return getLockSettings().checkPattern(patternToString(pattern), userId); } catch (RemoteException re) { @@ -319,8 +270,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPassword(String password, long challenge) { - final int userId = getCurrentOrCallingUserId(); + public byte[] verifyPassword(String password, long challenge, int userId) { try { return getLockSettings().verifyPassword(password, challenge, userId); } catch (RemoteException re) { @@ -334,8 +284,7 @@ public class LockPatternUtils { * @param password The password to check. * @return Whether the password matches the stored one. */ - public boolean checkPassword(String password) { - final int userId = getCurrentOrCallingUserId(); + public boolean checkPassword(String password, int userId) { try { return getLockSettings().checkPassword(password, userId); } catch (RemoteException re) { @@ -348,8 +297,7 @@ public class LockPatternUtils { * Note that this also clears vold's copy of the password. * @return Whether the vold password matches or not. */ - public boolean checkVoldPassword() { - final int userId = getCurrentOrCallingUserId(); + public boolean checkVoldPassword(int userId) { try { return getLockSettings().checkVoldPassword(userId); } catch (RemoteException re) { @@ -364,8 +312,7 @@ public class LockPatternUtils { * @param password The password to check. * @return Whether the password matches any in the history. */ - public boolean checkPasswordHistory(String password) { - int userId = getCurrentOrCallingUserId(); + public boolean checkPasswordHistory(String password, int userId) { String passwordHashString = new String( passwordToHash(password, userId), StandardCharsets.UTF_8); String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId); @@ -374,7 +321,7 @@ public class LockPatternUtils { } // Password History may be too long... int passwordHashLength = passwordHashString.length(); - int passwordHistoryLength = getRequestedPasswordHistoryLength(); + int passwordHistoryLength = getRequestedPasswordHistoryLength(userId); if(passwordHistoryLength == 0) { return false; } @@ -416,16 +363,8 @@ public class LockPatternUtils { * * @return True if the user has ever chosen a pattern. */ - public boolean isPatternEverChosen() { - return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, getCurrentOrCallingUserId()); - } - - /** - * Used by device policy manager to validate the current password - * information it has. - */ - public int getActivePasswordQuality() { - return getActivePasswordQuality(getCurrentOrCallingUserId()); + public boolean isPatternEverChosen(int userId) { + return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId); } /** @@ -448,10 +387,6 @@ public class LockPatternUtils { return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } - public void clearLock() { - clearLock(getCurrentOrCallingUserId()); - } - /** * Clear any lock pattern or password. */ @@ -479,16 +414,6 @@ public class LockPatternUtils { } /** - * Disable showing lock screen at all when the DevicePolicyManager allows it. - * This is only meaningful if pattern, pin or password are not set. - * - * @param disable Disables lock screen when true - */ - public void setLockScreenDisabled(boolean disable) { - setLockScreenDisabled(disable, getCurrentOrCallingUserId()); - } - - /** * Disable showing lock screen at all for a given user. * This is only meaningful if pattern, pin or password are not set. * @@ -505,21 +430,16 @@ public class LockPatternUtils { * * @return true if lock screen is disabled */ - public boolean isLockScreenDisabled() { - return !isSecure() && - getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId()); + public boolean isLockScreenDisabled(int userId) { + return !isSecure(userId) && + getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId); } /** * Save a lock pattern. * @param pattern The new pattern to save. - * @param savedPattern The previously saved pattern, or null if none + * @param userId the user whose pattern is to be saved. */ - public void saveLockPattern(List<LockPatternView.Cell> pattern, - String savedPattern) { - this.saveLockPattern(pattern, savedPattern, getCurrentOrCallingUserId()); - } - public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) { this.saveLockPattern(pattern, null, userId); } @@ -588,8 +508,7 @@ public class LockPatternUtils { updateCryptoUserInfo(userId); } - public void setOwnerInfoEnabled(boolean enabled) { - int userId = getCurrentOrCallingUserId(); + public void setOwnerInfoEnabled(boolean enabled, int userId) { setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId); updateCryptoUserInfo(userId); } @@ -598,11 +517,7 @@ public class LockPatternUtils { return getString(LOCK_SCREEN_OWNER_INFO, userId); } - public boolean isOwnerInfoEnabled() { - return isOwnerInfoEnabled(getCurrentOrCallingUserId()); - } - - private boolean isOwnerInfoEnabled(int userId) { + public boolean isOwnerInfoEnabled(int userId) { return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId); } @@ -724,21 +639,10 @@ public class LockPatternUtils { /** * Save a lock password. Does not ensure that the password is as good * as the requested mode, but will adjust the mode to be as good as the - * pattern. + * password. * @param password The password to save * @param savedPassword The previously saved lock password, or null if none * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} - */ - public void saveLockPassword(String password, String savedPassword, int quality) { - saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId()); - } - - /** - * Save a lock password. Does not ensure that the password is as good - * as the requested mode, but will adjust the mode to be as good as the - * pattern. - * @param password The password to save - * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} * @param userHandle The userId of the user to change the password for */ public void saveLockPassword(String password, String savedPassword, int quality, @@ -865,16 +769,6 @@ public class LockPatternUtils { } /** - * Retrieves the quality mode we're in. - * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} - * - * @return stored password quality - */ - public int getKeyguardStoredPasswordQuality() { - return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId()); - } - - /** * Retrieves the quality mode for {@param userHandle}. * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} * @@ -997,13 +891,6 @@ public class LockPatternUtils { } /** - * @return Whether the lock screen is secured. - */ - public boolean isSecure() { - return isSecure(getCurrentOrCallingUserId()); - } - - /** * @param userId the user for which to report the value * @return Whether the lock screen is secured. */ @@ -1012,13 +899,6 @@ public class LockPatternUtils { return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId); } - /** - * @return Whether the lock password is enabled - */ - public boolean isLockPasswordEnabled() { - return isLockPasswordEnabled(getCurrentOrCallingUserId()); - } - public boolean isLockPasswordEnabled(int userId) { return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId); } @@ -1035,10 +915,6 @@ public class LockPatternUtils { /** * @return Whether the lock pattern is enabled */ - public boolean isLockPatternEnabled() { - return isLockPatternEnabled(getCurrentOrCallingUserId()); - } - public boolean isLockPatternEnabled(int userId) { return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId); } @@ -1051,16 +927,14 @@ public class LockPatternUtils { /** * @return Whether the visible pattern is enabled. */ - public boolean isVisiblePatternEnabled() { - return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, getCurrentOrCallingUserId()); + public boolean isVisiblePatternEnabled(int userId) { + return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId); } /** * Set whether the visible pattern is enabled. */ - public void setVisiblePatternEnabled(boolean enabled) { - int userId = getCurrentOrCallingUserId(); - + public void setVisiblePatternEnabled(boolean enabled, int userId) { setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId); // Update for crypto if owner @@ -1095,9 +969,9 @@ public class LockPatternUtils { * pattern until the deadline has passed. * @return the chosen deadline. */ - public long setLockoutAttemptDeadline() { + public long setLockoutAttemptDeadline(int userId) { final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS; - setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, getCurrentOrCallingUserId()); + setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId); return deadline; } @@ -1106,8 +980,8 @@ public class LockPatternUtils { * attempt to enter his/her lock pattern, or 0 if the user is welcome to * enter a pattern. */ - public long getLockoutAttemptDeadline() { - final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, getCurrentOrCallingUserId()); + public long getLockoutAttemptDeadline(int userId) { + final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId); final long now = SystemClock.elapsedRealtime(); if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) { return 0L; @@ -1166,21 +1040,12 @@ public class LockPatternUtils { } } - public void setPowerButtonInstantlyLocks(boolean enabled) { - setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId()); - } - - public boolean getPowerButtonInstantlyLocks() { - return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, - getCurrentOrCallingUserId()); - } - - public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) { - setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId()); + public void setPowerButtonInstantlyLocks(boolean enabled, int userId) { + setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId); } - public List<ComponentName> getEnabledTrustAgents() { - return getEnabledTrustAgents(getCurrentOrCallingUserId()); + public boolean getPowerButtonInstantlyLocks(int userId) { + return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId); } public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) { @@ -1192,7 +1057,7 @@ public class LockPatternUtils { sb.append(cn.flattenToShortString()); } setString(ENABLED_TRUST_AGENTS, sb.toString(), userId); - getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId()); + getTrustManager().reportEnabledTrustAgentsChanged(userId); } public List<ComponentName> getEnabledTrustAgents(int userId) { @@ -1228,7 +1093,7 @@ public class LockPatternUtils { } public void setCredentialRequiredToDecrypt(boolean required) { - if (getCurrentUser() != UserHandle.USER_OWNER) { + if (ActivityManager.getCurrentUser() != UserHandle.USER_OWNER) { Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()"); return; } |
