diff options
59 files changed, 2389 insertions, 976 deletions
diff --git a/api/current.txt b/api/current.txt index df9438cbf525..93cc84362fd5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5644,8 +5644,10 @@ package android.app { method public static java.lang.String suppressedEffectsToString(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR; + field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20 field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8 field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2 + field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40 field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4 field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1 field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10 @@ -11000,6 +11002,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); + method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); @@ -11018,6 +11021,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; + field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 + field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 + field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 + field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 + field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 + field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 + field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } @@ -40035,8 +40045,12 @@ package android.telephony { field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT"; field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO"; field public static final int RESULT_CANCELLED = 2; // 0x2 + field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6 field public static final int RESULT_EXPIRED = 3; // 0x3 + field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8 field public static final int RESULT_IO_ERROR = 4; // 0x4 + field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7 + field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5 field public static final int RESULT_SUCCESSFUL = 1; // 0x1 field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1 field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index 752e0beb506b..9767e441453b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5852,8 +5852,10 @@ package android.app { method public static java.lang.String suppressedEffectsToString(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR; + field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20 field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8 field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2 + field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40 field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4 field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1 field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10 @@ -11723,6 +11725,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); + method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); @@ -11741,6 +11744,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; + field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 + field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 + field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 + field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 + field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 + field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 + field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } @@ -43544,8 +43554,12 @@ package android.telephony { field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO"; field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload"; field public static final int RESULT_CANCELLED = 2; // 0x2 + field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6 field public static final int RESULT_EXPIRED = 3; // 0x3 + field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8 field public static final int RESULT_IO_ERROR = 4; // 0x4 + field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7 + field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5 field public static final int RESULT_SUCCESSFUL = 1; // 0x1 field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1 field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index 08b297bad41d..702ec3bacf05 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5670,8 +5670,10 @@ package android.app { method public static java.lang.String suppressedEffectsToString(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR; + field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20 field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8 field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2 + field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40 field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4 field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1 field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10 @@ -11081,6 +11083,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); + method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); @@ -11097,8 +11100,16 @@ package android.content.pm { method public boolean isEnabled(); method public boolean isImmutable(); method public boolean isPinned(); + method public boolean isVisibleToPublisher(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; + field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 + field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 + field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 + field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 + field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 + field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 + field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } @@ -40416,8 +40427,12 @@ package android.telephony { field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT"; field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO"; field public static final int RESULT_CANCELLED = 2; // 0x2 + field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6 field public static final int RESULT_EXPIRED = 3; // 0x3 + field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8 field public static final int RESULT_IO_ERROR = 4; // 0x4 + field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7 + field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5 field public static final int RESULT_SUCCESSFUL = 1; // 0x1 field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1 field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2 diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index eb52cb7f9508..a52dc1e4e768 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -934,8 +934,14 @@ public class NotificationManager { public static final int PRIORITY_CATEGORY_CALLS = 1 << 3; /** Calls from repeat callers are prioritized. */ public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 4; + /** Alarms are prioritized */ + public static final int PRIORITY_CATEGORY_ALARMS = 1 << 5; + /** Media, system, game (catch-all for non-never suppressible sounds) are prioritized */ + public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 1 << 6; private static final int[] ALL_PRIORITY_CATEGORIES = { + PRIORITY_CATEGORY_ALARMS, + PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, PRIORITY_CATEGORY_REMINDERS, PRIORITY_CATEGORY_EVENTS, PRIORITY_CATEGORY_MESSAGES, @@ -1135,6 +1141,9 @@ public class NotificationManager { case PRIORITY_CATEGORY_MESSAGES: return "PRIORITY_CATEGORY_MESSAGES"; case PRIORITY_CATEGORY_CALLS: return "PRIORITY_CATEGORY_CALLS"; case PRIORITY_CATEGORY_REPEAT_CALLERS: return "PRIORITY_CATEGORY_REPEAT_CALLERS"; + case PRIORITY_CATEGORY_ALARMS: return "PRIORITY_CATEGORY_ALARMS"; + case PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER: + return "PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER"; default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory; } } diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 6b9c7537d710..2f78161b1729 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -18,6 +18,7 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.annotation.UserIdInt; import android.app.TaskStackBuilder; import android.content.ComponentName; @@ -100,6 +101,13 @@ public final class ShortcutInfo implements Parcelable { /** @hide When this is set, the bitmap icon is waiting to be saved. */ public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11; + /** + * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been + * installed yet. + * @hide + */ + public static final int FLAG_SHADOW = 1 << 12; + /** @hide */ @IntDef(flag = true, value = { @@ -158,6 +166,91 @@ public final class ShortcutInfo implements Parcelable { public @interface CloneFlags {} /** + * Shortcut is not disabled. + */ + public static final int DISABLED_REASON_NOT_DISABLED = 0; + + /** + * Shortcut has been disabled by the publisher app with the + * {@link ShortcutManager#disableShortcuts(List)} API. + */ + public static final int DISABLED_REASON_BY_APP = 1; + + /** + * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut + * no longer exists.) + */ + public static final int DISABLED_REASON_APP_CHANGED = 2; + + /** + * A disabled reason that's equal to or bigger than this is due to backup and restore issue. + * A shortcut with such a reason wil be visible to the launcher, but not to the publisher. + * ({@link #isVisibleToPublisher()} will be false.) + */ + private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100; + + /** + * Shortcut has been restored from the previous device, but the publisher app on the current + * device is of a lower version. The shortcut will not be usable until the app is upgraded to + * the same version or higher. + */ + public static final int DISABLED_REASON_VERSION_LOWER = 100; + + /** + * Shortcut has not been restored because the publisher app does not support backup and restore. + */ + public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; + + /** + * Shortcut has not been restored because the publisher app's signature has changed. + */ + public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; + + /** + * Shortcut has not been restored for unknown reason. + */ + public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; + + /** @hide */ + @IntDef(value = { + DISABLED_REASON_NOT_DISABLED, + DISABLED_REASON_BY_APP, + DISABLED_REASON_APP_CHANGED, + DISABLED_REASON_VERSION_LOWER, + DISABLED_REASON_BACKUP_NOT_SUPPORTED, + DISABLED_REASON_SIGNATURE_MISMATCH, + DISABLED_REASON_OTHER_RESTORE_ISSUE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisabledReason{} + + /** @hide */ + public static String getDisabledReasonLabel(@DisabledReason int disabledReason) { + switch (disabledReason) { + case DISABLED_REASON_NOT_DISABLED: + return "[Not disabled]"; + case DISABLED_REASON_BY_APP: + return "[Disabled: by app]"; + case DISABLED_REASON_APP_CHANGED: + return "[Disabled: app changed]"; + case DISABLED_REASON_VERSION_LOWER: + return "[Disabled: lower version]"; + case DISABLED_REASON_BACKUP_NOT_SUPPORTED: + return "[Disabled: backup not supported]"; + case DISABLED_REASON_SIGNATURE_MISMATCH: + return "[Disabled: signature mismatch]"; + case DISABLED_REASON_OTHER_RESTORE_ISSUE: + return "[Disabled: unknown restore issue]"; + } + return "[Disabled: unknown reason:" + disabledReason + "]"; + } + + /** @hide */ + public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) { + return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START; + } + + /** * Shortcut category for messaging related actions, such as chat. */ public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; @@ -240,6 +333,11 @@ public final class ShortcutInfo implements Parcelable { private final int mUserId; + /** @hide */ + public static final int VERSION_CODE_UNKNOWN = -1; + + private int mDisabledReason; + private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); @@ -352,6 +450,7 @@ public final class ShortcutInfo implements Parcelable { mActivity = source.mActivity; mFlags = source.mFlags; mLastChangedTimestamp = source.mLastChangedTimestamp; + mDisabledReason = source.mDisabledReason; // Just always keep it since it's cheep. mIconResId = source.mIconResId; @@ -615,13 +714,23 @@ public final class ShortcutInfo implements Parcelable { /** * @hide + * + * @isUpdating set true if it's "update", as opposed to "replace". */ - public void ensureUpdatableWith(ShortcutInfo source) { + public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) { + if (isUpdating) { + Preconditions.checkState(isVisibleToPublisher(), + "[Framework BUG] Invisible shortcuts can't be updated"); + } Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match"); Preconditions.checkState(mId.equals(source.mId), "ID must match"); Preconditions.checkState(mPackageName.equals(source.mPackageName), "Package name must match"); - Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable"); + + if (isVisibleToPublisher()) { + // Don't do this check for restore-blocked shortcuts. + Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable"); + } } /** @@ -638,7 +747,7 @@ public final class ShortcutInfo implements Parcelable { * @hide */ public void copyNonNullFieldsFrom(ShortcutInfo source) { - ensureUpdatableWith(source); + ensureUpdatableWith(source, /*isUpdating=*/ true); if (source.mActivity != null) { mActivity = source.mActivity; @@ -1169,6 +1278,19 @@ public final class ShortcutInfo implements Parcelable { return mDisabledMessageResId; } + /** @hide */ + public void setDisabledReason(@DisabledReason int reason) { + mDisabledReason = reason; + } + + /** + * Returns why a shortcut has been disabled. + */ + @DisabledReason + public int getDisabledReason() { + return mDisabledReason; + } + /** * Return the shortcut's categories. * @@ -1403,6 +1525,21 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_IMMUTABLE); } + /** @hide */ + public boolean isDynamicVisible() { + return isDynamic() && isVisibleToPublisher(); + } + + /** @hide */ + public boolean isPinnedVisible() { + return isPinned() && isVisibleToPublisher(); + } + + /** @hide */ + public boolean isManifestVisible() { + return isDeclaredInManifest() && isVisibleToPublisher(); + } + /** * Return if a shortcut is immutable, in which case it cannot be modified with any of * {@link ShortcutManager} APIs. @@ -1491,6 +1628,18 @@ public final class ShortcutInfo implements Parcelable { } /** + * When the system wasn't able to restore a shortcut, it'll still be registered to the system + * but disabled, and such shortcuts will not be visible to the publisher. They're still visible + * to launchers though. + * + * @hide + */ + @TestApi + public boolean isVisibleToPublisher() { + return !isDisabledForRestoreIssue(mDisabledReason); + } + + /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. * <ul> @@ -1668,6 +1817,7 @@ public final class ShortcutInfo implements Parcelable { mFlags = source.readInt(); mIconResId = source.readInt(); mLastChangedTimestamp = source.readLong(); + mDisabledReason = source.readInt(); if (source.readInt() == 0) { return; // key information only. @@ -1711,6 +1861,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeInt(mFlags); dest.writeInt(mIconResId); dest.writeLong(mLastChangedTimestamp); + dest.writeInt(mDisabledReason); if (hasKeyFieldsOnly()) { dest.writeInt(0); @@ -1808,6 +1959,11 @@ public final class ShortcutInfo implements Parcelable { sb.append(", flags=0x"); sb.append(Integer.toHexString(mFlags)); sb.append(" ["); + if ((mFlags & FLAG_SHADOW) != 0) { + // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so + // we don't have an isXxx for this. + sb.append("Sdw"); + } if (!isEnabled()) { sb.append("Dis"); } @@ -1848,7 +2004,9 @@ public final class ShortcutInfo implements Parcelable { sb.append("packageName="); sb.append(mPackageName); - sb.append(", activity="); + addIndentOrComma(sb, indent); + + sb.append("activity="); sb.append(mActivity); addIndentOrComma(sb, indent); @@ -1883,6 +2041,11 @@ public final class ShortcutInfo implements Parcelable { addIndentOrComma(sb, indent); + sb.append("disabledReason="); + sb.append(getDisabledReasonLabel(mDisabledReason)); + + addIndentOrComma(sb, indent); + sb.append("categories="); sb.append(mCategories); @@ -1953,7 +2116,7 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, - int flags, int iconResId, String iconResName, String bitmapPath) { + int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) { mUserId = userId; mId = id; mPackageName = packageName; @@ -1978,5 +2141,6 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; + mDisabledReason = disabledReason; } } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index ee8eed1906f4..3d2e1d1f1d24 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -206,8 +206,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba try { mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone .getAudioAttributes()) - .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY | - AudioAttributes.FLAG_BYPASS_MUTE) + .setFlags(AudioAttributes.FLAG_BYPASS_MUTE) .build()); mRingtone.play(); } catch (Throwable e) { diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 7bec898ac347..c5615ae6f8dc 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -76,10 +76,13 @@ public class ZenModeConfig implements Parcelable { private static final int DAY_MINUTES = 24 * 60; private static final int ZERO_VALUE_MS = 10 * SECONDS_MS; - private static final boolean DEFAULT_ALLOW_CALLS = true; + // Default allow categories set in readXml() from default_zen_mode_config.xml, fallback values: + private static final boolean DEFAULT_ALLOW_ALARMS = true; + private static final boolean DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER = true; + private static final boolean DEFAULT_ALLOW_CALLS = false; private static final boolean DEFAULT_ALLOW_MESSAGES = false; - private static final boolean DEFAULT_ALLOW_REMINDERS = true; - private static final boolean DEFAULT_ALLOW_EVENTS = true; + private static final boolean DEFAULT_ALLOW_REMINDERS = false; + private static final boolean DEFAULT_ALLOW_EVENTS = false; private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false; private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true; private static final boolean DEFAULT_ALLOW_SCREEN_ON = true; @@ -89,6 +92,8 @@ public class ZenModeConfig implements Parcelable { private static final String ZEN_ATT_VERSION = "version"; private static final String ZEN_ATT_USER = "user"; private static final String ALLOW_TAG = "allow"; + private static final String ALLOW_ATT_ALARMS = "alarms"; + private static final String ALLOW_ATT_MEDIA = "media_system_other"; private static final String ALLOW_ATT_CALLS = "calls"; private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers"; private static final String ALLOW_ATT_MESSAGES = "messages"; @@ -100,8 +105,6 @@ public class ZenModeConfig implements Parcelable { private static final String ALLOW_ATT_SCREEN_OFF = "visualScreenOff"; private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn"; - private static final String CONDITION_TAG = "condition"; - private static final String CONDITION_ATT_COMPONENT = "component"; private static final String CONDITION_ATT_ID = "id"; private static final String CONDITION_ATT_SUMMARY = "summary"; private static final String CONDITION_ATT_LINE1 = "line1"; @@ -123,6 +126,8 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_CREATION_TIME = "creationTime"; private static final String RULE_ATT_ENABLER = "enabler"; + public boolean allowAlarms = DEFAULT_ALLOW_ALARMS; + public boolean allowMediaSystemOther = DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER; public boolean allowCalls = DEFAULT_ALLOW_CALLS; public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS; public boolean allowMessages = DEFAULT_ALLOW_MESSAGES; @@ -161,6 +166,8 @@ public class ZenModeConfig implements Parcelable { } allowWhenScreenOff = source.readInt() == 1; allowWhenScreenOn = source.readInt() == 1; + allowAlarms = source.readInt() == 1; + allowMediaSystemOther = source.readInt() == 1; } @Override @@ -190,19 +197,23 @@ public class ZenModeConfig implements Parcelable { } dest.writeInt(allowWhenScreenOff ? 1 : 0); dest.writeInt(allowWhenScreenOn ? 1 : 0); + dest.writeInt(allowAlarms ? 1 : 0); + dest.writeInt(allowMediaSystemOther ? 1 : 0); } @Override public String toString() { return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[') .append("user=").append(user) + .append(",allowAlarms=").append(allowAlarms) + .append(",allowMediaSystemOther=").append(allowMediaSystemOther) + .append(",allowReminders=").append(allowReminders) + .append(",allowEvents=").append(allowEvents) .append(",allowCalls=").append(allowCalls) .append(",allowRepeatCallers=").append(allowRepeatCallers) .append(",allowMessages=").append(allowMessages) .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom)) .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom)) - .append(",allowReminders=").append(allowReminders) - .append(",allowEvents=").append(allowEvents) .append(",allowWhenScreenOff=").append(allowWhenScreenOff) .append(",allowWhenScreenOn=").append(allowWhenScreenOn) .append(",automaticRules=").append(automaticRules) @@ -218,9 +229,21 @@ public class ZenModeConfig implements Parcelable { if (user != to.user) { d.addLine("user", user, to.user); } + if (allowAlarms != to.allowAlarms) { + d.addLine("allowAlarms", allowAlarms, to.allowAlarms); + } + if (allowMediaSystemOther != to.allowMediaSystemOther) { + d.addLine("allowMediaSystemOther", allowMediaSystemOther, to.allowMediaSystemOther); + } if (allowCalls != to.allowCalls) { d.addLine("allowCalls", allowCalls, to.allowCalls); } + if (allowReminders != to.allowReminders) { + d.addLine("allowReminders", allowReminders, to.allowReminders); + } + if (allowEvents != to.allowEvents) { + d.addLine("allowEvents", allowEvents, to.allowEvents); + } if (allowRepeatCallers != to.allowRepeatCallers) { d.addLine("allowRepeatCallers", allowRepeatCallers, to.allowRepeatCallers); } @@ -233,12 +256,6 @@ public class ZenModeConfig implements Parcelable { if (allowMessagesFrom != to.allowMessagesFrom) { d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom); } - if (allowReminders != to.allowReminders) { - d.addLine("allowReminders", allowReminders, to.allowReminders); - } - if (allowEvents != to.allowEvents) { - d.addLine("allowEvents", allowEvents, to.allowEvents); - } if (allowWhenScreenOff != to.allowWhenScreenOff) { d.addLine("allowWhenScreenOff", allowWhenScreenOff, to.allowWhenScreenOff); } @@ -335,7 +352,9 @@ public class ZenModeConfig implements Parcelable { if (!(o instanceof ZenModeConfig)) return false; if (o == this) return true; final ZenModeConfig other = (ZenModeConfig) o; - return other.allowCalls == allowCalls + return other.allowAlarms == allowAlarms + && other.allowMediaSystemOther == allowMediaSystemOther + && other.allowCalls == allowCalls && other.allowRepeatCallers == allowRepeatCallers && other.allowMessages == allowMessages && other.allowCallsFrom == allowCallsFrom @@ -351,10 +370,10 @@ public class ZenModeConfig implements Parcelable { @Override public int hashCode() { - return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom, - allowMessagesFrom, allowReminders, allowEvents, allowWhenScreenOff, - allowWhenScreenOn, - user, automaticRules, manualRule); + return Objects.hash(allowAlarms, allowMediaSystemOther, allowCalls, + allowRepeatCallers, allowMessages, + allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents, + allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule); } private static String toDayList(int[] days) { @@ -413,10 +432,12 @@ public class ZenModeConfig implements Parcelable { } if (type == XmlPullParser.START_TAG) { if (ALLOW_TAG.equals(tag)) { - rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false); + rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, + DEFAULT_ALLOW_CALLS); rt.allowRepeatCallers = safeBoolean(parser, ALLOW_ATT_REPEAT_CALLERS, DEFAULT_ALLOW_REPEAT_CALLERS); - rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false); + rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, + DEFAULT_ALLOW_MESSAGES); rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS, DEFAULT_ALLOW_REMINDERS); rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS, DEFAULT_ALLOW_EVENTS); @@ -438,6 +459,9 @@ public class ZenModeConfig implements Parcelable { safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF); rt.allowWhenScreenOn = safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON); + rt.allowAlarms = safeBoolean(parser, ALLOW_ATT_ALARMS, DEFAULT_ALLOW_ALARMS); + rt.allowMediaSystemOther = safeBoolean(parser, ALLOW_ATT_MEDIA, + DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER); } else if (MANUAL_TAG.equals(tag)) { rt.manualRule = readRuleXml(parser); } else if (AUTOMATIC_TAG.equals(tag)) { @@ -468,6 +492,8 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom)); out.attribute(null, ALLOW_ATT_SCREEN_OFF, Boolean.toString(allowWhenScreenOff)); out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowWhenScreenOn)); + out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms)); + out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowMediaSystemOther)); out.endTag(null, ALLOW_TAG); if (manualRule != null) { @@ -654,6 +680,12 @@ public class ZenModeConfig implements Parcelable { if (!allowWhenScreenOn) { suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON; } + if (allowAlarms) { + priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS; + } + if (allowMediaSystemOther) { + priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER; + } priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders); priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders); return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders, @@ -680,10 +712,13 @@ public class ZenModeConfig implements Parcelable { public void applyNotificationPolicy(Policy policy) { if (policy == null) return; - allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0; - allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0; + allowAlarms = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0; + allowMediaSystemOther = (policy.priorityCategories + & Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0; allowEvents = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_EVENTS) != 0; allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0; + allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0; + allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0; allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0; allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom); diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index ad26f23a70d7..ddfc00c9163a 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -129,7 +129,6 @@ public class Hyphenator { final String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb"; final File patternFile = new File(SYSTEM_HYPHENATOR_LOCATION, patternFilename); if (!patternFile.canRead()) { - Log.e(TAG, "hyphenation patterns for " + patternFile + " not found or unreadable"); mDataAddress = 0; } else { long address; @@ -230,6 +229,11 @@ public class Hyphenator { loadData("tk", 2, 2); // Turkmen loadData("und-Ethi", 1, 1); // Any language in Ethiopic script + // Following two hyphenators do not have pattern files but there is some special logic + // based on language. + loadData("ca", 2, 2); // Catalan + loadData("pl", 2, 2); // Polish + // English locales that fall back to en-US. The data is // from CLDR. It's all English locales, minus the locales whose // parent is en-001 (from supplementalData.xml, under <parentLocales>). @@ -267,7 +271,7 @@ public class Hyphenator { } }; - private static native long nBuildHyphenator(/* non-zero */ long dataAddress, + private static native long nBuildHyphenator(long dataAddress, @NonNull String langTag, @IntRange(from = 1) int minPrefix, @IntRange(from = 1) int minSuffix); } diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index 0f21c5c85f4b..d7851171cd67 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -329,8 +329,6 @@ public final class AccessibilityCache { final long oldParentId = oldInfo.getParentNodeId(); if (info.getParentNodeId() != oldParentId) { clearSubTreeLocked(windowId, oldParentId); - } else { - oldInfo.recycle(); } } diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml index 5f4199acfe7e..1e4c03ee9637 100644 --- a/core/res/res/xml/default_zen_mode_config.xml +++ b/core/res/res/xml/default_zen_mode_config.xml @@ -19,5 +19,5 @@ <!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. --> <zen version="2"> - <allow calls="true" messages="false" reminders="true" events="true" /> + <allow alarms="true" media_system_other="true" calls="false" messages="false" reminders="false" events="false" /> </zen> diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index afb1193657e1..f7a90b0a65ec 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -22,10 +22,11 @@ #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include <log/log.h> +#include <errno.h> +#include <fcntl.h> #include <inttypes.h> -#include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> +#include <sys/types.h> #include <unistd.h> #include <sys/mman.h> @@ -366,4 +367,4 @@ void GraphicsStatsService::finishDump(Dump* dump) { } } /* namespace uirenderer */ -} /* namespace android */
\ No newline at end of file +} /* namespace android */ diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 26ead3d1b54d..20405d3b725c 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -202,6 +202,22 @@ public final class AudioAttributes implements Parcelable { * @see #SUPPRESSIBLE_USAGES */ public final static int SUPPRESSIBLE_NEVER = 3; + /** + * @hide + * Denotes a usage for alarms, + * will be muted when the Zen mode doesn't allow alarms + * @see #SUPPRESSIBLE_USAGES + */ + public final static int SUPPRESSIBLE_ALARM = 4; + /** + * @hide + * Denotes a usage for all other sounds not caught in SUPPRESSIBLE_NOTIFICATION, + * SUPPRESSIBLE_CALL,SUPPRESSIBLE_NEVER or SUPPRESSIBLE_ALARM. + * This includes media, system, game, navigation, the assistant, and more. + * These will be muted when the Zen mode doesn't allow media/system/other. + * @see #SUPPRESSIBLE_USAGES + */ + public final static int SUPPRESSIBLE_MEDIA_SYSTEM_OTHER = 5; /** * @hide @@ -221,6 +237,13 @@ public final class AudioAttributes implements Parcelable { SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT, SUPPRESSIBLE_NOTIFICATION); SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_ACCESSIBILITY, SUPPRESSIBLE_NEVER); SUPPRESSIBLE_USAGES.put(USAGE_VOICE_COMMUNICATION, SUPPRESSIBLE_NEVER); + SUPPRESSIBLE_USAGES.put(USAGE_ALARM, SUPPRESSIBLE_ALARM); + SUPPRESSIBLE_USAGES.put(USAGE_MEDIA, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); + SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_SONIFICATION, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); + SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); + SUPPRESSIBLE_USAGES.put(USAGE_GAME, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); + SUPPRESSIBLE_USAGES.put(USAGE_VOICE_COMMUNICATION_SIGNALLING, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); + SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANT, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER); } /** diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 6a8a222254db..9b167c82be6d 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4675,6 +4675,18 @@ message MetricsEvent { // OS: P DIALOG_LOG_PERSIST = 1225; + // ACTION: DND Settings > Priority only allows > Alarms toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ALLOW_ALARMS = 1162; + + // ACTION: DND Settings > Priority only allows > Media toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ALLOW_MEDIA = 1163; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 05db922bccbd..7075e67b9852 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -358,8 +358,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; - private final LaunchingTaskPositioner mTaskPositioner; - private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -462,8 +460,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowManager = mService.mWindowManager; mStackId = stackId; mCurrentUser = mService.mUserController.getCurrentUserId(); - mTaskPositioner = windowingMode == WINDOWING_MODE_FREEFORM - ? new LaunchingTaskPositioner() : null; mTmpRect2.setEmpty(); setWindowingMode(windowingMode); setActivityType(activityType); @@ -504,11 +500,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mDisplayId = activityDisplay.mDisplayId; mBounds = bounds != null ? new Rect(bounds) : null; mFullscreen = mBounds == null; - if (mTaskPositioner != null) { - activityDisplay.mDisplay.getSize(mTmpSize); - mTaskPositioner.setDisplaySize(mTmpSize); - mTaskPositioner.configure(mBounds); - } + onParentChanged(); activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); @@ -536,9 +528,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai display.removeChild(this); } mDisplayId = INVALID_DISPLAY; - if (mTaskPositioner != null) { - mTaskPositioner.reset(); - } } /** Removes the stack completely. Also calls WindowManager to do the same on its side. */ @@ -642,9 +631,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai void setBounds(Rect bounds) { mBounds = mFullscreen ? null : new Rect(bounds); - if (mTaskPositioner != null) { - mTaskPositioner.configure(bounds); - } } ActivityRecord topRunningActivityLocked() { @@ -5137,10 +5123,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) { - if (mTaskPositioner == null) { + if (!task.inFreeformWindowingMode()) { return false; } - mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout); + mStackSupervisor.getLaunchingTaskPositioner() + .updateDefaultBounds(task, mTaskHistory, windowLayout); + return true; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index bac71c7672eb..c5cb5bbcdd73 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -293,6 +293,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D WindowManagerService mWindowManager; DisplayManager mDisplayManager; + LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner(); + /** Counter for next free stack ID to use for dynamic activity stacks. */ private int mNextFreeStackId = 0; @@ -2138,6 +2140,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D || mService.mSupportsFreeformWindowManagement; } + LaunchingTaskPositioner getLaunchingTaskPositioner() { + return mTaskPositioner; + } + protected <T extends ActivityStack> T getStack(int stackId) { for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { final T stack = mActivityDisplays.valueAt(i).getStack(stackId); diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java index 2c161cd934b4..0dc73e98f492 100644 --- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java +++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java @@ -64,23 +64,12 @@ class LaunchingTaskPositioner { private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2; private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3; - private boolean mDefaultStartBoundsConfigurationSet = false; private final Rect mAvailableRect = new Rect(); private final Rect mTmpProposal = new Rect(); private final Rect mTmpOriginal = new Rect(); - private int mDefaultFreeformStartX; - private int mDefaultFreeformStartY; - private int mDefaultFreeformWidth; - private int mDefaultFreeformHeight; - private int mDefaultFreeformStepHorizontal; - private int mDefaultFreeformStepVertical; private final Point mDisplaySize = new Point(); - void setDisplaySize(Point size) { - mDisplaySize.set(size.x, size.y); - } - /** * Tries to set task's bound in a way that it won't collide with any other task. By colliding * we mean that two tasks have left-top corner very close to each other, so one might get @@ -93,52 +82,47 @@ class LaunchingTaskPositioner { */ void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks, @Nullable ActivityInfo.WindowLayout windowLayout) { - if (!mDefaultStartBoundsConfigurationSet) { - return; - } + updateAvailableRect(task, mAvailableRect); + if (windowLayout == null) { - positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight); + positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect), + getFreeformHeight(mAvailableRect)); return; } - int width = getFinalWidth(windowLayout); - int height = getFinalHeight(windowLayout); + int width = getFinalWidth(windowLayout, mAvailableRect); + int height = getFinalHeight(windowLayout, mAvailableRect); int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK; int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (verticalGravity == Gravity.TOP) { if (horizontalGravity == Gravity.RIGHT) { - positionTopRight(task, tasks, width, height); + positionTopRight(task, tasks, mAvailableRect, width, height); } else { - positionTopLeft(task, tasks, width, height); + positionTopLeft(task, tasks, mAvailableRect, width, height); } } else if (verticalGravity == Gravity.BOTTOM) { if (horizontalGravity == Gravity.RIGHT) { - positionBottomRight(task, tasks, width, height); + positionBottomRight(task, tasks, mAvailableRect, width, height); } else { - positionBottomLeft(task, tasks, width, height); + positionBottomLeft(task, tasks, mAvailableRect, width, height); } } else { // Some fancy gravity setting that we don't support yet. We just put the activity in the // center. Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity + ", positioning in the center instead."); - positionCenter(task, tasks, width, height); + positionCenter(task, tasks, mAvailableRect, width, height); } } - void configure(Rect availableSpace) { - if (availableSpace == null) { - mAvailableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); + private void updateAvailableRect(TaskRecord task, Rect availableRect) { + final Rect stackBounds = task.getStack().mBounds; + + if (stackBounds != null) { + availableRect.set(stackBounds); } else { - mAvailableRect.set(availableSpace); + task.getStack().getDisplay().mDisplay.getSize(mDisplaySize); + availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); } - - mDefaultFreeformStartX = getFreeformStartLeft(mAvailableRect); - mDefaultFreeformStartY = getFreeformStartTop(mAvailableRect); - mDefaultFreeformWidth = getFreeformWidth(mAvailableRect); - mDefaultFreeformHeight = getFreeformHeight(mAvailableRect); - mDefaultFreeformStepHorizontal = getHorizontalStep(mAvailableRect); - mDefaultFreeformStepVertical = getVerticalStep(mAvailableRect); - mDefaultStartBoundsConfigurationSet = true; } @VisibleForTesting @@ -173,72 +157,79 @@ class LaunchingTaskPositioner { - private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) { - int width = mDefaultFreeformWidth; + private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { + int width = getFreeformWidth(availableRect); if (windowLayout.width > 0) { width = windowLayout.width; } if (windowLayout.widthFraction > 0) { - width = (int) (mAvailableRect.width() * windowLayout.widthFraction); + width = (int) (availableRect.width() * windowLayout.widthFraction); } return width; } - private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) { - int height = mDefaultFreeformHeight; + private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { + int height = getFreeformHeight(availableRect); if (windowLayout.height > 0) { height = windowLayout.height; } if (windowLayout.heightFraction > 0) { - height = (int) (mAvailableRect.height() * windowLayout.heightFraction); + height = (int) (availableRect.height() * windowLayout.heightFraction); } return height; } - private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height, - mAvailableRect.left + width, mAvailableRect.bottom); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.left, availableRect.bottom - height, + availableRect.left + width, availableRect.bottom); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height, - mAvailableRect.right, mAvailableRect.bottom); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.right - width, availableRect.bottom - height, + availableRect.right, availableRect.bottom); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.left, mAvailableRect.top, - mAvailableRect.left + width, mAvailableRect.top + height); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.left, availableRect.top, + availableRect.left + width, availableRect.top + height); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top, - mAvailableRect.right, mAvailableRect.top + height); - position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + mTmpProposal.set(availableRect.right - width, availableRect.top, + availableRect.right, availableRect.top + height); + position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, + SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width, - int height) { - mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY, - mDefaultFreeformStartX + width, mDefaultFreeformStartY + height); - position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN); + private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, + Rect availableRect, int width, int height) { + final int defaultFreeformLeft = getFreeformStartLeft(availableRect); + final int defaultFreeformTop = getFreeformStartTop(availableRect); + mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop, + defaultFreeformLeft + width, defaultFreeformTop + height); + position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART, + SHIFT_POLICY_DIAGONAL_DOWN); } - private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal, - boolean allowRestart, int shiftPolicy) { + private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect, + Rect proposal, boolean allowRestart, int shiftPolicy) { mTmpOriginal.set(proposal); boolean restarted = false; while (boundsConflict(proposal, tasks)) { // Unfortunately there is already a task at that spot, so we need to look for some // other place. - shiftStartingPoint(proposal, shiftPolicy); - if (shiftedTooFar(proposal, shiftPolicy)) { + shiftStartingPoint(proposal, availableRect, shiftPolicy); + if (shiftedTooFar(proposal, availableRect, shiftPolicy)) { // We don't want the task to go outside of the stack, because it won't look // nice. Depending on the starting point we either restart, or immediately give up. if (!allowRestart) { @@ -247,13 +238,13 @@ class LaunchingTaskPositioner { } // We must have started not from the top. Let's restart from there because there // might be some space there. - proposal.set(mAvailableRect.left, mAvailableRect.top, - mAvailableRect.left + proposal.width(), - mAvailableRect.top + proposal.height()); + proposal.set(availableRect.left, availableRect.top, + availableRect.left + proposal.width(), + availableRect.top + proposal.height()); restarted = true; } - if (restarted && (proposal.left > mDefaultFreeformStartX - || proposal.top > mDefaultFreeformStartY)) { + if (restarted && (proposal.left > getFreeformStartLeft(availableRect) + || proposal.top > getFreeformStartTop(availableRect))) { // If we restarted and crossed the initial position, let's not struggle anymore. // The user already must have ton of tasks visible, we can just smack the new // one in the center. @@ -264,27 +255,30 @@ class LaunchingTaskPositioner { task.updateOverrideConfiguration(proposal); } - private boolean shiftedTooFar(Rect start, int shiftPolicy) { + private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) { switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - return start.left < mAvailableRect.left; + return start.left < availableRect.left; case SHIFT_POLICY_HORIZONTAL_RIGHT: - return start.right > mAvailableRect.right; + return start.right > availableRect.right; default: // SHIFT_POLICY_DIAGONAL_DOWN - return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom; + return start.right > availableRect.right || start.bottom > availableRect.bottom; } } - private void shiftStartingPoint(Rect posposal, int shiftPolicy) { + private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) { + final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect); + final int defaultFreeformStepVertical = getVerticalStep(availableRect); + switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - posposal.offset(-mDefaultFreeformStepHorizontal, 0); + posposal.offset(-defaultFreeformStepHorizontal, 0); break; case SHIFT_POLICY_HORIZONTAL_RIGHT: - posposal.offset(mDefaultFreeformStepHorizontal, 0); + posposal.offset(defaultFreeformStepHorizontal, 0); break; default: // SHIFT_POLICY_DIAGONAL_DOWN: - posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical); + posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical); break; } } @@ -323,8 +317,4 @@ class LaunchingTaskPositioner { return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE; } - - void reset() { - mDefaultStartBoundsConfigurationSet = false; - } } diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 6506cf7fa189..494317334f43 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -184,11 +184,15 @@ public final class PlaybackActivityMonitor } } + private static final int FLAGS_FOR_SILENCE_OVERRIDE = + AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY | + AudioAttributes.FLAG_BYPASS_MUTE; + private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) { if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED || apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { - if ((apc.getAudioAttributes().getAllFlags() & - AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0 && + if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE) + == FLAGS_FOR_SILENCE_OVERRIDE && apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM && mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, apc.getClientPid(), apc.getClientUid()) == diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 0b11479a162a..664d2f9789f0 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -784,6 +784,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mService.enforcePhoneStatePermission(pid, uid); } mFlags = flags; + if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { + final long token = Binder.clearCallingIdentity(); + try { + mService.setGlobalPrioritySession(MediaSessionRecord.this); + } finally { + Binder.restoreCallingIdentity(token); + } + } mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE); } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index b102dde30a94..aa652445c45a 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -178,17 +178,6 @@ public class MediaSessionService extends SystemService implements Monitor { return; } if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { - if (mGlobalPrioritySession != record) { - Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession - + " to " + record); - mGlobalPrioritySession = record; - if (user != null && user.mPriorityStack.contains(record)) { - // Handle the global priority session separately. - // Otherwise, it will be the media button session even after it becomes - // inactive because it has been the lastly played media app. - user.mPriorityStack.removeSession(record); - } - } if (DEBUG_KEY_EVENT) { Log.d(TAG, "Global priority session is updated, active=" + record.isActive()); } @@ -204,6 +193,24 @@ public class MediaSessionService extends SystemService implements Monitor { } } + public void setGlobalPrioritySession(MediaSessionRecord record) { + synchronized (mLock) { + FullUserRecord user = getFullUserRecordLocked(record.getUserId()); + if (mGlobalPrioritySession != record) { + Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession + + " to " + record); + mGlobalPrioritySession = record; + if (user != null && user.mPriorityStack.contains(record)) { + // Handle the global priority session separately. + // Otherwise, it can be the media button session regardless of the active state + // because it or other system components might have been the lastly played media + // app. + user.mPriorityStack.removeSession(record); + } + } + } + } + private List<MediaSessionRecord> getActiveSessionsLocked(int userId) { List<MediaSessionRecord> records = new ArrayList<>(); if (userId == UserHandle.USER_ALL) { diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java index a7a2743dfc7f..abf2900654fd 100644 --- a/services/core/java/com/android/server/notification/ZenModeFiltering.java +++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java @@ -117,15 +117,19 @@ public class ZenModeFiltering { ZenLog.traceIntercepted(record, "alarmsOnly"); return true; case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: - if (isAlarm(record)) { - // Alarms are always priority - return false; - } // allow user-prioritized packages through in priority mode if (record.getPackagePriority() == Notification.PRIORITY_MAX) { ZenLog.traceNotIntercepted(record, "priorityApp"); return false; } + + if (isAlarm(record)) { + if (!config.allowAlarms) { + ZenLog.traceIntercepted(record, "!allowAlarms"); + return true; + } + return false; + } if (isCall(record)) { if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(mContext, extras(record))) { @@ -159,6 +163,15 @@ public class ZenModeFiltering { } return false; } + AudioAttributes aa = record.getAudioAttributes(); + if (aa != null && AudioAttributes.SUPPRESSIBLE_USAGES.get(aa.getUsage()) == + AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) { + if (!config.allowMediaSystemOther) { + ZenLog.traceIntercepted(record, "!allowMediaSystemOther"); + return true; + } + return false; + } ZenLog.traceIntercepted(record, "!priority"); return true; default: diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 9fcc67df500a..710684f4351d 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -59,6 +59,7 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.server.LocalServices; @@ -87,7 +88,7 @@ public class ZenModeHelper { private final Context mContext; private final H mHandler; private final SettingsObserver mSettingsObserver; - private final AppOpsManager mAppOps; + @VisibleForTesting protected final AppOpsManager mAppOps; protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final ZenModeFiltering mFiltering; @@ -102,9 +103,9 @@ public class ZenModeHelper { private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1"; private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2"; - private int mZenMode; + @VisibleForTesting protected int mZenMode; private int mUser = UserHandle.USER_SYSTEM; - protected ZenModeConfig mConfig; + @VisibleForTesting protected ZenModeConfig mConfig; private AudioManagerInternal mAudioManager; protected PackageManager mPm; private long mSuppressedEffects; @@ -595,8 +596,9 @@ public class ZenModeHelper { pw.println(config); return; } - pw.printf("allow(calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s," + pw.printf("allow(alarms=%b,media=%bcalls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s," + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n", + config.allowAlarms, config.allowMediaSystemOther, config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom), config.allowRepeatCallers, config.allowMessages, ZenModeConfig.sourceToString(config.allowMessagesFrom), @@ -813,7 +815,8 @@ public class ZenModeHelper { } } - private void applyRestrictions() { + @VisibleForTesting + protected void applyRestrictions() { final boolean zen = mZenMode != Global.ZEN_MODE_OFF; // notification restrictions @@ -822,6 +825,10 @@ public class ZenModeHelper { // call restrictions final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0; + // alarm restrictions + final boolean muteAlarms = zen && !mConfig.allowAlarms; + // alarm restrictions + final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther; // total silence restrictions final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; @@ -833,13 +840,18 @@ public class ZenModeHelper { applyRestrictions(muteNotifications || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { applyRestrictions(muteCalls || muteEverything, usage); + } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) { + applyRestrictions(muteAlarms || muteEverything, usage); + } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) { + applyRestrictions(muteMediaAndSystemSounds || muteEverything, usage); } else { applyRestrictions(muteEverything, usage); } } } - private void applyRestrictions(boolean mute, int usage) { + @VisibleForTesting + protected void applyRestrictions(boolean mute, int usage) { final String[] exceptionPackages = null; // none (for now) mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage, mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java index f922ad195ac2..cedf47633c78 100644 --- a/services/core/java/com/android/server/pm/ShortcutLauncher.java +++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java @@ -83,11 +83,16 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } + @Override + protected boolean canRestoreAnyVersion() { + // Launcher's pinned shortcuts can be restored to an older version. + return true; + } + /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ - @Override - protected void onRestoreBlocked() { + private void onRestoreBlocked() { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); @@ -101,15 +106,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } @Override - protected void onRestored() { - // Nothing to do. + protected void onRestored(int restoreBlockReason) { + // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or + // DISABLED_REASON_BACKUP_NOT_SUPPORTED. + // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version + // code for launchers. + if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + onRestoreBlocked(); + } } /** * Pin the given shortcuts, replacing the current pinned ones. */ public void pinShortcuts(@UserIdInt int packageUserId, - @NonNull String packageName, @NonNull List<String> ids) { + @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) { final ShortcutPackage packageShortcuts = mShortcutUser.getPackageShortcutsIfExists(packageName); if (packageShortcuts == null) { @@ -124,8 +135,12 @@ class ShortcutLauncher extends ShortcutPackageItem { } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); - // Pin shortcuts. Make sure only pin the ones that were visible to the caller. - // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. + // Actually pin shortcuts. + // This logic here is to make sure a launcher cannot pin a shortcut that is floating + // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher. + // In this case, technically the shortcut doesn't exist to this launcher, so it can't + // pin it. + // (Maybe unnecessarily strict...) final ArraySet<String> newSet = new ArraySet<>(); @@ -135,8 +150,10 @@ class ShortcutLauncher extends ShortcutPackageItem { if (si == null) { continue; } - if (si.isDynamic() || si.isManifestShortcut() - || (prevSet != null && prevSet.contains(id))) { + if (si.isDynamic() + || si.isManifestShortcut() + || (prevSet != null && prevSet.contains(id)) + || forPinRequest) { newSet.add(id); } } @@ -155,7 +172,7 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** - * Return true if the given shortcut is pinned by this launcher. + * Return true if the given shortcut is pinned by this launcher.<code></code> */ public boolean hasPinned(ShortcutInfo shortcut) { final ArraySet<String> pinned = @@ -164,10 +181,10 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** - * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)} + * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)} */ public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId, - String id) { + String id, boolean forPinRequest) { final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId); final ArrayList<String> pinnedList; if (pinnedSet != null) { @@ -178,21 +195,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } pinnedList.add(id); - pinShortcuts(packageUserId, packageName, pinnedList); + pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest); } boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } - public void ensureVersionInfo() { + public void ensurePackageInfo() { final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures( getPackageName(), getPackageUserId()); if (pi == null) { Slog.w(TAG, "Package not found: " + getPackageName()); return; } - getPackageInfo().updateVersionInfo(pi); + getPackageInfo().updateFromPackageInfo(pi); } /** @@ -201,6 +218,10 @@ class ShortcutLauncher extends ShortcutPackageItem { @Override public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { + if (forBackup && !getPackageInfo().isBackupAllowed()) { + // If an launcher app doesn't support backup&restore, then nothing to do. + return; + } final int size = mPinnedShortcuts.size(); if (size == 0) { return; // Nothing to write. @@ -209,7 +230,7 @@ class ShortcutLauncher extends ShortcutPackageItem { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId()); - getPackageInfo().saveToXml(out); + getPackageInfo().saveToXml(out, forBackup); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 6fc1e738408e..a4bec1d562bf 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -84,6 +84,7 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_DISABLED_MESSAGE = "dmessage"; private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid"; private static final String ATTR_DISABLED_MESSAGE_RES_NAME = "dmessagename"; + private static final String ATTR_DISABLED_REASON = "disabled-reason"; private static final String ATTR_INTENT_LEGACY = "intent"; private static final String ATTR_INTENT_NO_EXTRA = "intent-base"; private static final String ATTR_RANK = "rank"; @@ -156,13 +157,25 @@ class ShortcutPackage extends ShortcutPackageItem { } @Override - protected void onRestoreBlocked() { - // Can't restore due to version/signature mismatch. Remove all shortcuts. - mShortcuts.clear(); + protected boolean canRestoreAnyVersion() { + return false; } @Override - protected void onRestored() { + protected void onRestored(int restoreBlockReason) { + // Shortcuts have been restored. + // - Unshadow all shortcuts. + // - Set disabled reason. + // - Disable if needed. + for (int i = mShortcuts.size() - 1; i >= 0; i--) { + ShortcutInfo si = mShortcuts.valueAt(i); + si.clearFlags(ShortcutInfo.FLAG_SHADOW); + + si.setDisabledReason(restoreBlockReason); + if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + si.addFlags(ShortcutInfo.FLAG_DISABLED); + } + } // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. refreshPinnedFlags(); @@ -176,31 +189,47 @@ class ShortcutPackage extends ShortcutPackageItem { return mShortcuts.get(id); } - private void ensureNotImmutable(@Nullable ShortcutInfo shortcut) { - if (shortcut != null && shortcut.isImmutable()) { + public boolean isShortcutExistsAndInvisibleToPublisher(String id) { + ShortcutInfo si = findShortcutById(id); + return si != null && !si.isVisibleToPublisher(); + } + + public boolean isShortcutExistsAndVisibleToPublisher(String id) { + ShortcutInfo si = findShortcutById(id); + return si != null && si.isVisibleToPublisher(); + } + + private void ensureNotImmutable(@Nullable ShortcutInfo shortcut, boolean ignoreInvisible) { + if (shortcut != null && shortcut.isImmutable() + && (!ignoreInvisible || shortcut.isVisibleToPublisher())) { throw new IllegalArgumentException( "Manifest shortcut ID=" + shortcut.getId() + " may not be manipulated via APIs"); } } - public void ensureNotImmutable(@NonNull String id) { - ensureNotImmutable(mShortcuts.get(id)); + public void ensureNotImmutable(@NonNull String id, boolean ignoreInvisible) { + ensureNotImmutable(mShortcuts.get(id), ignoreInvisible); } - public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds) { + public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds, + boolean ignoreInvisible) { for (int i = shortcutIds.size() - 1; i >= 0; i--) { - ensureNotImmutable(shortcutIds.get(i)); + ensureNotImmutable(shortcutIds.get(i), ignoreInvisible); } } - public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts) { + public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts, + boolean ignoreInvisible) { for (int i = shortcuts.size() - 1; i >= 0; i--) { - ensureNotImmutable(shortcuts.get(i).getId()); + ensureNotImmutable(shortcuts.get(i).getId(), ignoreInvisible); } } - private ShortcutInfo deleteShortcutInner(@NonNull String id) { + /** + * Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible. + */ + private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) { final ShortcutInfo shortcut = mShortcuts.remove(id); if (shortcut != null) { mShortcutUser.mService.removeIconLocked(shortcut); @@ -210,10 +239,14 @@ class ShortcutPackage extends ShortcutPackageItem { return shortcut; } - private void addShortcutInner(@NonNull ShortcutInfo newShortcut) { + /** + * Force replace a shortcut. If there's already a shortcut with the same ID, it'll be removed, + * even if it's invisible. + */ + private void forceReplaceShortcutInner(@NonNull ShortcutInfo newShortcut) { final ShortcutService s = mShortcutUser.mService; - deleteShortcutInner(newShortcut.getId()); + forceDeleteShortcutInner(newShortcut.getId()); // Extract Icon and update the icon res ID and the bitmap path. s.saveIconAndFixUpShortcutLocked(newShortcut); @@ -222,11 +255,12 @@ class ShortcutPackage extends ShortcutPackageItem { } /** - * Add a shortcut, or update one with the same ID, with taking over existing flags. + * Add a shortcut. If there's already a one with the same ID, it'll be removed, even if it's + * invisible. * * It checks the max number of dynamic shortcuts. */ - public void addOrUpdateDynamicShortcut(@NonNull ShortcutInfo newShortcut) { + public void addOrReplaceDynamicShortcut(@NonNull ShortcutInfo newShortcut) { Preconditions.checkArgument(newShortcut.isEnabled(), "add/setDynamicShortcuts() cannot publish disabled shortcuts"); @@ -242,7 +276,7 @@ class ShortcutPackage extends ShortcutPackageItem { } else { // It's an update case. // Make sure the target is updatable. (i.e. should be mutable.) - oldShortcut.ensureUpdatableWith(newShortcut); + oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); wasPinned = oldShortcut.isPinned(); } @@ -252,7 +286,7 @@ class ShortcutPackage extends ShortcutPackageItem { newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); } - addShortcutInner(newShortcut); + forceReplaceShortcutInner(newShortcut); } /** @@ -273,7 +307,7 @@ class ShortcutPackage extends ShortcutPackageItem { } if (removeList != null) { for (int i = removeList.size() - 1; i >= 0; i--) { - deleteShortcutInner(removeList.get(i)); + forceDeleteShortcutInner(removeList.get(i)); } } } @@ -281,13 +315,13 @@ class ShortcutPackage extends ShortcutPackageItem { /** * Remove all dynamic shortcuts. */ - public void deleteAllDynamicShortcuts() { + public void deleteAllDynamicShortcuts(boolean ignoreInvisible) { final long now = mShortcutUser.mService.injectCurrentTimeMillis(); boolean changed = false; for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); - if (si.isDynamic()) { + if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) { changed = true; si.setTimestamp(now); @@ -307,9 +341,10 @@ class ShortcutPackage extends ShortcutPackageItem { * @return true if it's actually removed because it wasn't pinned, or false if it's still * pinned. */ - public boolean deleteDynamicWithId(@NonNull String shortcutId) { + public boolean deleteDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible) { final ShortcutInfo removed = deleteOrDisableWithId( - shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false); + shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible, + ShortcutInfo.DISABLED_REASON_NOT_DISABLED); return removed == null; } @@ -320,9 +355,11 @@ class ShortcutPackage extends ShortcutPackageItem { * @return true if it's actually removed because it wasn't pinned, or false if it's still * pinned. */ - private boolean disableDynamicWithId(@NonNull String shortcutId) { + private boolean disableDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible, + int disabledReason) { final ShortcutInfo disabled = deleteOrDisableWithId( - shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false); + shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false, ignoreInvisible, + disabledReason); return disabled == null; } @@ -331,9 +368,10 @@ class ShortcutPackage extends ShortcutPackageItem { * is pinned, it'll remain as a pinned shortcut but will be disabled. */ public void disableWithId(@NonNull String shortcutId, String disabledMessage, - int disabledMessageResId, boolean overrideImmutable) { + int disabledMessageResId, boolean overrideImmutable, boolean ignoreInvisible, + int disabledReason) { final ShortcutInfo disabled = deleteOrDisableWithId(shortcutId, /* disable =*/ true, - overrideImmutable); + overrideImmutable, ignoreInvisible, disabledReason); if (disabled != null) { if (disabledMessage != null) { @@ -348,14 +386,18 @@ class ShortcutPackage extends ShortcutPackageItem { @Nullable private ShortcutInfo deleteOrDisableWithId(@NonNull String shortcutId, boolean disable, - boolean overrideImmutable) { + boolean overrideImmutable, boolean ignoreInvisible, int disabledReason) { + Preconditions.checkState( + (disable == (disabledReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED)), + "disable and disabledReason disagree: " + disable + " vs " + disabledReason); final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId); - if (oldShortcut == null || !oldShortcut.isEnabled()) { + if (oldShortcut == null || !oldShortcut.isEnabled() + && (ignoreInvisible && !oldShortcut.isVisibleToPublisher())) { return null; // Doesn't exist or already disabled. } if (!overrideImmutable) { - ensureNotImmutable(oldShortcut); + ensureNotImmutable(oldShortcut, /*ignoreInvisible=*/ true); } if (oldShortcut.isPinned()) { @@ -363,6 +405,10 @@ class ShortcutPackage extends ShortcutPackageItem { oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST); if (disable) { oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED); + // Do not overwrite the disabled reason if one is alreay set. + if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + oldShortcut.setDisabledReason(disabledReason); + } } oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis()); @@ -373,7 +419,7 @@ class ShortcutPackage extends ShortcutPackageItem { return oldShortcut; } else { - deleteShortcutInner(shortcutId); + forceDeleteShortcutInner(shortcutId); return null; } } @@ -381,11 +427,25 @@ class ShortcutPackage extends ShortcutPackageItem { public void enableWithId(@NonNull String shortcutId) { final ShortcutInfo shortcut = mShortcuts.get(shortcutId); if (shortcut != null) { - ensureNotImmutable(shortcut); + ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true); shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED); + shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); } } + public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) { + final ShortcutInfo source = mShortcuts.get(shortcut.getId()); + Preconditions.checkNotNull(source); + + mShortcutUser.mService.validateShortcutForPinRequest(shortcut); + + shortcut.addFlags(ShortcutInfo.FLAG_PINNED); + + forceReplaceShortcutInner(shortcut); + + adjustRanks(); + } + /** * Called after a launcher updates the pinned set. For each shortcut in this package, * set FLAG_PINNED if any launcher has pinned it. Otherwise, clear it. @@ -693,7 +753,27 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageInfo().getVersionCode(), pi.versionCode)); } - getPackageInfo().updateVersionInfo(pi); + getPackageInfo().updateFromPackageInfo(pi); + final int newVersionCode = getPackageInfo().getVersionCode(); + + // See if there are any shortcuts that were prevented restoring because the app was of a + // lower version, and re-enable them. + for (int i = mShortcuts.size() - 1; i >= 0; i--) { + final ShortcutInfo si = mShortcuts.valueAt(i); + if (si.getDisabledReason() != ShortcutInfo.DISABLED_REASON_VERSION_LOWER) { + continue; + } + if (getPackageInfo().getBackupSourceVersionCode() > newVersionCode) { + if (ShortcutService.DEBUG) { + Slog.d(TAG, String.format("Shortcut %s require version %s, still not restored.", + si.getId(), getPackageInfo().getBackupSourceVersionCode())); + } + continue; + } + Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId())); + si.clearFlags(ShortcutInfo.FLAG_DISABLED); + si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); + } // For existing shortcuts, update timestamps if they have any resources. // Also check if shortcuts' activities are still main activities. Otherwise, disable them. @@ -713,7 +793,8 @@ class ShortcutPackage extends ShortcutPackageItem { Slog.w(TAG, String.format( "%s is no longer main activity. Disabling shorcut %s.", getPackageName(), si.getId())); - if (disableDynamicWithId(si.getId())) { + if (disableDynamicWithId(si.getId(), /*ignoreInvisible*/ false, + ShortcutInfo.DISABLED_REASON_APP_CHANGED)) { continue; // Actually removed. } // Still pinned, so fall-through and possibly update the resources. @@ -809,7 +890,7 @@ class ShortcutPackage extends ShortcutPackageItem { // Note even if enabled=false, we still need to update all fields, so do it // regardless. - addShortcutInner(newShortcut); // This will clean up the old one too. + forceReplaceShortcutInner(newShortcut); // This will clean up the old one too. if (!newDisabled && toDisableList != null) { // Still alive, don't remove. @@ -831,7 +912,8 @@ class ShortcutPackage extends ShortcutPackageItem { final String id = toDisableList.valueAt(i); disableWithId(id, /* disable message =*/ null, /* disable message resid */ 0, - /* overrideImmutable=*/ true); + /* overrideImmutable=*/ true, /*ignoreInvisible=*/ false, + ShortcutInfo.DISABLED_REASON_APP_CHANGED); } removeOrphans(); } @@ -869,7 +951,7 @@ class ShortcutPackage extends ShortcutPackageItem { service.wtf("Found manifest shortcuts in excess list."); continue; } - deleteDynamicWithId(shortcut.getId()); + deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true); } } @@ -1075,7 +1157,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (ret != 0) { return ret; } - // If they're stil tie, just sort by their IDs. + // If they're still tie, just sort by their IDs. // This may happen with updateShortcuts() -- see // the testUpdateShortcuts_noManifestShortcuts() test. return a.getId().compareTo(b.getId()); @@ -1257,25 +1339,34 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount); ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime); - getPackageInfo().saveToXml(out); + getPackageInfo().saveToXml(out, forBackup); for (int j = 0; j < size; j++) { - saveShortcut(out, mShortcuts.valueAt(j), forBackup); + saveShortcut(out, mShortcuts.valueAt(j), forBackup, + getPackageInfo().isBackupAllowed()); } out.endTag(null, TAG_ROOT); } - private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup) + private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup, + boolean appSupportsBackup) throws IOException, XmlPullParserException { final ShortcutService s = mShortcutUser.mService; if (forBackup) { if (!(si.isPinned() && si.isEnabled())) { - return; // We only backup pinned shortcuts that are enabled. + // We only backup pinned shortcuts that are enabled. + // Note, this means, shortcuts that are restored but are blocked restore, e.g. due + // to a lower version code, will not be ported to a new device. + return; } } + final boolean shouldBackupDetails = + !forBackup // It's not backup + || appSupportsBackup; // Or, it's a backup and app supports backup. + // Note: at this point no shortcuts should have bitmaps pending save, but if they do, // just remove the bitmap. if (si.isIconPendingSave()) { @@ -1292,20 +1383,31 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_TEXT, si.getText()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_NAME, si.getTextResName()); - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage()); - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID, - si.getDisabledMessageResourceId()); - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME, - si.getDisabledMessageResName()); + if (shouldBackupDetails) { + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage()); + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID, + si.getDisabledMessageResourceId()); + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME, + si.getDisabledMessageResName()); + } + ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason()); ShortcutService.writeAttr(out, ATTR_TIMESTAMP, si.getLastChangedTimestamp()); if (forBackup) { // Don't write icon information. Also drop the dynamic flag. - ShortcutService.writeAttr(out, ATTR_FLAGS, - si.getFlags() & - ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES + + int flags = si.getFlags() & + ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES | ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE - | ShortcutInfo.FLAG_DYNAMIC)); + | ShortcutInfo.FLAG_DYNAMIC); + ShortcutService.writeAttr(out, ATTR_FLAGS, flags); + + // Set the publisher version code at every backup. + final int packageVersionCode = getPackageInfo().getVersionCode(); + if (packageVersionCode == 0) { + s.wtf("Package version code should be available at this point."); + // However, 0 is a valid version code, so we just go ahead with it... + } } else { // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored // as dynamic. @@ -1317,26 +1419,28 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath()); } - { - final Set<String> cat = si.getCategories(); - if (cat != null && cat.size() > 0) { - out.startTag(null, TAG_CATEGORIES); - XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]), - NAME_CATEGORIES, out); - out.endTag(null, TAG_CATEGORIES); + if (shouldBackupDetails) { + { + final Set<String> cat = si.getCategories(); + if (cat != null && cat.size() > 0) { + out.startTag(null, TAG_CATEGORIES); + XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]), + NAME_CATEGORIES, out); + out.endTag(null, TAG_CATEGORIES); + } + } + final Intent[] intentsNoExtras = si.getIntentsNoExtras(); + final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); + final int numIntents = intentsNoExtras.length; + for (int i = 0; i < numIntents; i++) { + out.startTag(null, TAG_INTENT); + ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); + ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); + out.endTag(null, TAG_INTENT); } - } - final Intent[] intentsNoExtras = si.getIntentsNoExtras(); - final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); - final int numIntents = intentsNoExtras.length; - for (int i = 0; i < numIntents; i++) { - out.startTag(null, TAG_INTENT); - ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); - ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); - out.endTag(null, TAG_INTENT); - } - ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); + ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); + } out.endTag(null, TAG_SHORTCUT); } @@ -1356,6 +1460,7 @@ class ShortcutPackage extends ShortcutPackageItem { ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET); + final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1369,10 +1474,11 @@ class ShortcutPackage extends ShortcutPackageItem { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: ret.getPackageInfo().loadFromXml(parser, fromBackup); + continue; case TAG_SHORTCUT: final ShortcutInfo si = parseShortcut(parser, packageName, - shortcutUser.getUserId()); + shortcutUser.getUserId(), fromBackup); // Don't use addShortcut(), we don't need to save the icon. ret.mShortcuts.put(si.getId(), si); @@ -1385,7 +1491,8 @@ class ShortcutPackage extends ShortcutPackageItem { } private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName, - @UserIdInt int userId) throws IOException, XmlPullParserException { + @UserIdInt int userId, boolean fromBackup) + throws IOException, XmlPullParserException { String id; ComponentName activityComponent; // Icon icon; @@ -1398,6 +1505,7 @@ class ShortcutPackage extends ShortcutPackageItem { String disabledMessage; int disabledMessageResId; String disabledMessageResName; + int disabledReason; Intent intentLegacy; PersistableBundle intentPersistableExtrasLegacy = null; ArrayList<Intent> intents = new ArrayList<>(); @@ -1408,6 +1516,7 @@ class ShortcutPackage extends ShortcutPackageItem { int iconResId; String iconResName; String bitmapPath; + int backupVersionCode; ArraySet<String> categories = null; id = ShortcutService.parseStringAttribute(parser, ATTR_ID); @@ -1424,6 +1533,7 @@ class ShortcutPackage extends ShortcutPackageItem { ATTR_DISABLED_MESSAGE_RES_ID); disabledMessageResName = ShortcutService.parseStringAttribute(parser, ATTR_DISABLED_MESSAGE_RES_NAME); + disabledReason = ShortcutService.parseIntAttribute(parser, ATTR_DISABLED_REASON); intentLegacy = ShortcutService.parseIntentAttributeNoDefault(parser, ATTR_INTENT_LEGACY); rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK); lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP); @@ -1480,6 +1590,19 @@ class ShortcutPackage extends ShortcutPackageItem { intents.add(intentLegacy); } + + if ((disabledReason == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) + && ((flags & ShortcutInfo.FLAG_DISABLED) != 0)) { + // We didn't used to have the disabled reason, so if a shortcut is disabled + // and has no reason, we assume it was disabled by publisher. + disabledReason = ShortcutInfo.DISABLED_REASON_BY_APP; + } + + // All restored shortcuts are initially "shadow". + if (fromBackup) { + flags |= ShortcutInfo.FLAG_SHADOW; + } + return new ShortcutInfo( userId, id, packageName, activityComponent, /* icon =*/ null, title, titleResId, titleResName, text, textResId, textResName, @@ -1487,7 +1610,7 @@ class ShortcutPackage extends ShortcutPackageItem { categories, intents.toArray(new Intent[intents.size()]), rank, extras, lastChangedTimestamp, flags, - iconResId, iconResName, bitmapPath); + iconResId, iconResName, bitmapPath, disabledReason); } private static Intent parseIntent(XmlPullParser parser) @@ -1602,6 +1725,20 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both resource and bitmap icons"); } + if (si.isEnabled() + != (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)) { + failed = true; + Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + + " isEnabled() and getDisabledReason() disagree: " + + si.isEnabled() + " vs " + si.getDisabledReason()); + } + if ((si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) + && (getPackageInfo().getBackupSourceVersionCode() + == ShortcutInfo.VERSION_CODE_UNKNOWN)) { + failed = true; + Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + + " RESTORED_VERSION_LOWER with no backup source version code."); + } if (s.isDummyMainActivity(si.getActivity())) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java index e5a2f5acbf89..3a9bbc8926ed 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java @@ -18,6 +18,7 @@ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.PackageInfo; +import android.content.pm.ShortcutInfo; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -45,32 +46,45 @@ class ShortcutPackageInfo { static final String TAG_ROOT = "package-info"; private static final String ATTR_VERSION = "version"; private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time"; + private static final String ATTR_BACKUP_SOURCE_VERSION = "bk_src_version"; + private static final String ATTR_BACKUP_ALLOWED = "allow-backup"; + private static final String ATTR_BACKUP_SOURCE_BACKUP_ALLOWED = "bk_src_backup-allowed"; private static final String ATTR_SHADOW = "shadow"; private static final String TAG_SIGNATURE = "signature"; private static final String ATTR_SIGNATURE_HASH = "hash"; - private static final int VERSION_UNKNOWN = -1; - /** * When true, this package information was restored from the previous device, and the app hasn't * been installed yet. */ private boolean mIsShadow; - private int mVersionCode = VERSION_UNKNOWN; + private int mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; + private int mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; private long mLastUpdateTime; private ArrayList<byte[]> mSigHashes; + // mBackupAllowed didn't used to be parsisted, so we don't restore it from a file. + // mBackupAllowed will always start with false, and will have been updated before making a + // backup next time, which works file. + // We just don't want to print an uninitialzied mBackupAlldowed value on dumpsys, so + // we use this boolean to control dumpsys. + private boolean mBackupAllowedInitialized; + private boolean mBackupAllowed; + private boolean mBackupSourceBackupAllowed; + private ShortcutPackageInfo(int versionCode, long lastUpdateTime, ArrayList<byte[]> sigHashes, boolean isShadow) { mVersionCode = versionCode; mLastUpdateTime = lastUpdateTime; mIsShadow = isShadow; mSigHashes = sigHashes; + mBackupAllowed = false; // By default, we assume false. + mBackupSourceBackupAllowed = false; } public static ShortcutPackageInfo newEmpty() { - return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0, + return new ShortcutPackageInfo(ShortcutInfo.VERSION_CODE_UNKNOWN, /* last update time =*/ 0, new ArrayList<>(0), /* isShadow */ false); } @@ -86,15 +100,33 @@ class ShortcutPackageInfo { return mVersionCode; } + public int getBackupSourceVersionCode() { + return mBackupSourceVersionCode; + } + + @VisibleForTesting + public boolean isBackupSourceBackupAllowed() { + return mBackupSourceBackupAllowed; + } + public long getLastUpdateTime() { return mLastUpdateTime; } - /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */ - public void updateVersionInfo(@NonNull PackageInfo pi) { + public boolean isBackupAllowed() { + return mBackupAllowed; + } + + /** + * Set {@link #mVersionCode}, {@link #mLastUpdateTime} and {@link #mBackupAllowed} + * from a {@link PackageInfo}. + */ + public void updateFromPackageInfo(@NonNull PackageInfo pi) { if (pi != null) { mVersionCode = pi.versionCode; mLastUpdateTime = pi.lastUpdateTime; + mBackupAllowed = ShortcutService.shouldBackupApp(pi); + mBackupAllowedInitialized = true; } } @@ -102,23 +134,24 @@ class ShortcutPackageInfo { return mSigHashes.size() > 0; } - public boolean canRestoreTo(ShortcutService s, PackageInfo target) { - if (!s.shouldBackupApp(target)) { + //@DisabledReason + public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) { + if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) { + Slog.w(TAG, "Can't restore: Package signature mismatch"); + return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; + } + if (!ShortcutService.shouldBackupApp(currentPackage) || !mBackupSourceBackupAllowed) { // "allowBackup" was true when backed up, but now false. - Slog.w(TAG, "Can't restore: package no longer allows backup"); - return false; + Slog.w(TAG, "Can't restore: package didn't or doesn't allow backup"); + return ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED; } - if (target.versionCode < mVersionCode) { + if (!anyVersionOkay && (currentPackage.versionCode < mBackupSourceVersionCode)) { Slog.w(TAG, String.format( "Can't restore: package current version %d < backed up version %d", - target.versionCode, mVersionCode)); - return false; - } - if (!BackupUtils.signaturesMatch(mSigHashes, target)) { - Slog.w(TAG, "Can't restore: Package signature mismatch"); - return false; + currentPackage.versionCode, mBackupSourceVersionCode)); + return ShortcutInfo.DISABLED_REASON_VERSION_LOWER; } - return true; + return ShortcutInfo.DISABLED_REASON_NOT_DISABLED; } @VisibleForTesting @@ -132,6 +165,8 @@ class ShortcutPackageInfo { final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false); + ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi); + ret.mBackupSourceVersionCode = pi.versionCode; return ret; } @@ -151,13 +186,19 @@ class ShortcutPackageInfo { mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); } - public void saveToXml(XmlSerializer out) throws IOException { + public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode); ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime); ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow); + ShortcutService.writeAttr(out, ATTR_BACKUP_ALLOWED, mBackupAllowed); + + ShortcutService.writeAttr(out, ATTR_BACKUP_SOURCE_VERSION, mBackupSourceVersionCode); + ShortcutService.writeAttr(out, + ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, mBackupSourceBackupAllowed); + for (int i = 0; i < mSigHashes.size(); i++) { out.startTag(null, TAG_SIGNATURE); @@ -171,7 +212,9 @@ class ShortcutPackageInfo { public void loadFromXml(XmlPullParser parser, boolean fromBackup) throws IOException, XmlPullParserException { - final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); + // Don't use the version code from the backup file. + final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION, + ShortcutInfo.VERSION_CODE_UNKNOWN); final long lastUpdateTime = ShortcutService.parseLongAttribute( parser, ATTR_LAST_UPDATE_TIME); @@ -180,6 +223,20 @@ class ShortcutPackageInfo { final boolean shadow = fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); + // We didn't used to save these attributes, and all backed up shortcuts were from + // apps that support backups, so the default values take this fact into consideration. + final int backupSourceVersion = ShortcutService.parseIntAttribute(parser, + ATTR_BACKUP_SOURCE_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN); + + // Note the only time these "true" default value is used is when restoring from an old + // build that didn't save ATTR_BACKUP_ALLOWED, and that means all the data included in + // a backup file were from apps that support backup, so we can just use "true" as the + // default. + final boolean backupAllowed = ShortcutService.parseBooleanAttribute( + parser, ATTR_BACKUP_ALLOWED, true); + final boolean backupSourceBackupAllowed = ShortcutService.parseBooleanAttribute( + parser, ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, true); + final ArrayList<byte[]> hashes = new ArrayList<>(); final int outerDepth = parser.getDepth(); @@ -207,11 +264,28 @@ class ShortcutPackageInfo { ShortcutService.warnForInvalidTag(depth, tag); } - // Successfully loaded; replace the feilds. - mVersionCode = versionCode; + // Successfully loaded; replace the fields. + if (fromBackup) { + mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; + mBackupSourceVersionCode = versionCode; + mBackupSourceBackupAllowed = backupAllowed; + } else { + mVersionCode = versionCode; + mBackupSourceVersionCode = backupSourceVersion; + mBackupSourceBackupAllowed = backupSourceBackupAllowed; + } mLastUpdateTime = lastUpdateTime; mIsShadow = shadow; mSigHashes = hashes; + + // Note we don't restore it from the file because it didn't used to be saved. + // We always start by assuming backup is disabled for the current package, + // and this field will have been updated before we actually create a backup, at the same + // time when we update the version code. + // Until then, the value of mBackupAllowed shouldn't matter, but we don't want to print + // a false flag on dumpsys, so set mBackupAllowedInitialized to false. + mBackupAllowed = false; + mBackupAllowedInitialized = false; } public void dump(PrintWriter pw, String prefix) { @@ -223,6 +297,7 @@ class ShortcutPackageInfo { pw.print(prefix); pw.print(" IsShadow: "); pw.print(mIsShadow); + pw.print(mIsShadow ? " (not installed)" : " (installed)"); pw.println(); pw.print(prefix); @@ -230,6 +305,25 @@ class ShortcutPackageInfo { pw.print(mVersionCode); pw.println(); + if (mBackupAllowedInitialized) { + pw.print(prefix); + pw.print(" Backup Allowed: "); + pw.print(mBackupAllowed); + pw.println(); + } + + if (mBackupSourceVersionCode != ShortcutInfo.VERSION_CODE_UNKNOWN) { + pw.print(prefix); + pw.print(" Backup source version: "); + pw.print(mBackupSourceVersionCode); + pw.println(); + + pw.print(prefix); + pw.print(" Backup source backup allowed: "); + pw.print(mBackupSourceBackupAllowed); + pw.println(); + } + pw.print(prefix); pw.print(" Last package update time: "); pw.print(mLastUpdateTime); diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java index e59d69f4c563..97b7b590514a 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.annotation.NonNull; import android.content.pm.PackageInfo; +import android.content.pm.ShortcutInfo; import android.util.Slog; import com.android.internal.util.Preconditions; @@ -101,51 +102,42 @@ abstract class ShortcutPackageItem { final ShortcutService s = mShortcutUser.mService; if (!s.isPackageInstalled(mPackageName, mPackageUserId)) { if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Package still not installed: %s user=%d", + Slog.d(TAG, String.format("Package still not installed: %s/u%d", mPackageName, mPackageUserId)); } return; // Not installed, no need to restore yet. } - boolean blockRestore = false; + int restoreBlockReason; + int currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; + if (!mPackageInfo.hasSignatures()) { - s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId + s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId + " but signatures not found in the restore data."); - blockRestore = true; - } - if (!blockRestore) { + restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; + } else { final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId); - if (!mPackageInfo.canRestoreTo(s, pi)) { - // Package is now installed, but can't restore. Let the subclass do the cleanup. - blockRestore = true; - } + currentVersionCode = pi.versionCode; + restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion()); } - if (blockRestore) { - onRestoreBlocked(); - } else { - if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName, - mPackageUserId, getOwnerUserId())); - } - onRestored(); + if (ShortcutService.DEBUG) { + Slog.d(TAG, String.format("Restoring package: %s/u%d (version=%d) %s for u%d", + mPackageName, mPackageUserId, currentVersionCode, + ShortcutInfo.getDisabledReasonLabel(restoreBlockReason), + getOwnerUserId())); } + onRestored(restoreBlockReason); + // Either way, it's no longer a shadow. mPackageInfo.setShadow(false); s.scheduleSaveUser(mPackageUserId); } - /** - * Called when the new package can't be restored because it has a lower version number - * or different signatures. - */ - protected abstract void onRestoreBlocked(); + protected abstract boolean canRestoreAnyVersion(); - /** - * Called when the new package is successfully restored. - */ - protected abstract void onRestored(); + protected abstract void onRestored(int restoreBlockReason); public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup) throws IOException, XmlPullParserException; diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java index 3cf4200b52c9..866c46c643ee 100644 --- a/services/core/java/com/android/server/pm/ShortcutParser.java +++ b/services/core/java/com/android/server/pm/ShortcutParser.java @@ -337,6 +337,9 @@ public class ShortcutParser { (enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED) | ShortcutInfo.FLAG_IMMUTABLE | ((iconResId != 0) ? ShortcutInfo.FLAG_HAS_ICON_RES : 0); + final int disabledReason = + enabled ? ShortcutInfo.DISABLED_REASON_NOT_DISABLED + : ShortcutInfo.DISABLED_REASON_BY_APP; // Note we don't need to set resource names here yet. They'll be set when they're about // to be published. @@ -363,6 +366,7 @@ public class ShortcutParser { flags, iconResId, null, // icon res name - null); // bitmap path + null, // bitmap path + disabledReason); } } diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java index 8a8128db9d16..3e44de989c7c 100644 --- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java +++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java @@ -300,10 +300,12 @@ class ShortcutRequestPinProcessor { final ShortcutInfo existing = ps.findShortcutById(inShortcut.getId()); final boolean existsAlready = existing != null; + final boolean existingIsVisible = existsAlready && existing.isVisibleToPublisher(); if (DEBUG) { Slog.d(TAG, "requestPinnedShortcut: package=" + inShortcut.getPackage() + " existsAlready=" + existsAlready + + " existingIsVisible=" + existingIsVisible + " shortcut=" + inShortcut.toInsecureString()); } @@ -378,7 +380,6 @@ class ShortcutRequestPinProcessor { // manifest shortcut.) Preconditions.checkArgument(shortcutInfo.isEnabled(), "Shortcut ID=" + shortcutInfo + " already exists but disabled."); - } private boolean startRequestConfirmActivity(ComponentName activity, int launcherUserId, @@ -463,7 +464,7 @@ class ShortcutRequestPinProcessor { launcher.attemptToRestoreIfNeededAndSave(); if (launcher.hasPinned(original)) { if (DEBUG) { - Slog.d(TAG, "Shortcut " + original + " already pinned."); + Slog.d(TAG, "Shortcut " + original + " already pinned."); // This too. } return true; } @@ -497,7 +498,7 @@ class ShortcutRequestPinProcessor { if (original.getActivity() == null) { original.setActivity(mService.getDummyMainActivity(appPackageName)); } - ps.addOrUpdateDynamicShortcut(original); + ps.addOrReplaceDynamicShortcut(original); } // Pin the shortcut. @@ -505,13 +506,14 @@ class ShortcutRequestPinProcessor { Slog.d(TAG, "Pinning " + shortcutId); } - launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId); + launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId, + /*forPinRequest=*/ true); if (current == null) { if (DEBUG) { Slog.d(TAG, "Removing " + shortcutId + " as dynamic"); } - ps.deleteDynamicWithId(shortcutId); + ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false); } ps.adjustRanks(); // Shouldn't be needed, but just in case. diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 27560c5f13ce..9d8679639559 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -553,6 +553,9 @@ public class ShortcutService extends IShortcutService.Stub { public Lifecycle(Context context) { super(context); + if (DEBUG) { + Binder.LOG_RUNTIME_EXCEPTION = true; + } mService = new ShortcutService(context); } @@ -738,6 +741,10 @@ public class ShortcutService extends IShortcutService.Stub { return parseLongAttribute(parser, attribute) == 1; } + static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) { + return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1; + } + static int parseIntAttribute(XmlPullParser parser, String attribute) { return (int) parseLongAttribute(parser, attribute); } @@ -835,6 +842,8 @@ public class ShortcutService extends IShortcutService.Stub { static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException { if (value) { writeAttr(out, name, "1"); + } else { + writeAttr(out, name, "0"); } } @@ -1689,7 +1698,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); fillInDefaultActivity(newShortcuts); @@ -1709,12 +1718,12 @@ public class ShortcutService extends IShortcutService.Stub { } // First, remove all un-pinned; dynamic shortcuts - ps.deleteAllDynamicShortcuts(); + ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); // Then, add/update all. We need to make sure to take over "pinned" flag. for (int i = 0; i < size; i++) { final ShortcutInfo newShortcut = newShortcuts.get(i); - ps.addOrUpdateDynamicShortcut(newShortcut); + ps.addOrReplaceDynamicShortcut(newShortcut); } // Lastly, adjust the ranks. @@ -1740,7 +1749,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); // For update, don't fill in the default activity. Having null activity means // "don't update the activity" here. @@ -1761,7 +1770,9 @@ public class ShortcutService extends IShortcutService.Stub { fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); final ShortcutInfo target = ps.findShortcutById(source.getId()); - if (target == null) { + + // Invisible shortcuts can't be updated. + if (target == null || !target.isVisibleToPublisher()) { continue; } @@ -1808,7 +1819,7 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, + public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId) { verifyCaller(packageName, userId); @@ -1820,7 +1831,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); fillInDefaultActivity(newShortcuts); @@ -1845,7 +1856,7 @@ public class ShortcutService extends IShortcutService.Stub { newShortcut.setRankChanged(); // Add it. - ps.addOrUpdateDynamicShortcut(newShortcut); + ps.addOrReplaceDynamicShortcut(newShortcut); } // Lastly, adjust the ranks. @@ -1901,6 +1912,22 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()), "Calling application must have a foreground activity or a foreground service"); + // If it's a pin shortcut request, and there's already a shortcut with the same ID + // that's not visible to the caller (i.e. restore-blocked; meaning it's pinned by + // someone already), then we just replace the existing one with this new one, + // and then proceed the rest of the process. + if (shortcut != null) { + final ShortcutPackage ps = getPackageShortcutsForPublisherLocked( + packageName, userId); + final String id = shortcut.getId(); + if (ps.isShortcutExistsAndInvisibleToPublisher(id)) { + + ps.updateInvisibleShortcutForPinRequestWith(shortcut); + + packageShortcutsChanged(packageName, userId); + } + } + // Send request to the launcher, if supported. ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, extras, userId, resultIntent); @@ -1922,15 +1949,21 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, + /*ignoreInvisible=*/ true); final String disabledMessageString = (disabledMessage == null) ? null : disabledMessage.toString(); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - ps.disableWithId(Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)), + final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); + if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { + continue; + } + ps.disableWithId(id, disabledMessageString, disabledMessageResId, - /* overrideImmutable=*/ false); + /* overrideImmutable=*/ false, /*ignoreInvisible=*/ true, + ShortcutInfo.DISABLED_REASON_BY_APP); } // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks. @@ -1951,10 +1984,15 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, + /*ignoreInvisible=*/ true); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - ps.enableWithId((String) shortcutIds.get(i)); + final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); + if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { + continue; + } + ps.enableWithId(id); } } packageShortcutsChanged(packageName, userId); @@ -1973,11 +2011,15 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, + /*ignoreInvisible=*/ true); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - ps.deleteDynamicWithId( - Preconditions.checkStringNotEmpty((String) shortcutIds.get(i))); + final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); + if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { + continue; + } + ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true); } // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks. @@ -1996,7 +2038,7 @@ public class ShortcutService extends IShortcutService.Stub { throwIfUserLockedL(userId); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.deleteAllDynamicShortcuts(); + ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); } packageShortcutsChanged(packageName, userId); @@ -2013,7 +2055,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isDynamic); + ShortcutInfo::isDynamicVisible); } } @@ -2027,7 +2069,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isManifestShortcut); + ShortcutInfo::isManifestVisible); } } @@ -2041,7 +2083,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isPinned); + ShortcutInfo::isPinnedVisible); } } @@ -2513,7 +2555,7 @@ public class ShortcutService extends IShortcutService.Stub { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId); launcher.attemptToRestoreIfNeededAndSave(); - launcher.pinShortcuts(userId, packageName, shortcutIds); + launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false); } packageShortcutsChanged(packageName, userId); @@ -3343,7 +3385,7 @@ public class ShortcutService extends IShortcutService.Stub { return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP); } - boolean shouldBackupApp(PackageInfo pi) { + static boolean shouldBackupApp(PackageInfo pi) { return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; } @@ -3371,7 +3413,7 @@ public class ShortcutService extends IShortcutService.Stub { // Set the version code for the launchers. // We shouldn't do this for publisher packages, because we don't want to update the // version code without rescanning the manifest. - user.forAllLaunchers(launcher -> launcher.ensureVersionInfo()); + user.forAllLaunchers(launcher -> launcher.ensurePackageInfo()); // Save to the filesystem. scheduleSaveUser(userId); diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 55e6d28a166e..48eccd02db64 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -364,9 +364,6 @@ class ShortcutUser { private void saveShortcutPackageItem(XmlSerializer out, ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException { if (forBackup) { - if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) { - return; // Don't save. - } if (spi.getPackageUserId() != spi.getOwnerUserId()) { return; // Don't save cross-user information. } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 6a5ecfaa7c47..ca3dd058660c 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -64,6 +64,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final PendingIntent mAnomalyAlarmIntent; private final PendingIntent mPollingAlarmIntent; private final BroadcastReceiver mAppUpdateReceiver; + private final BroadcastReceiver mUserUpdateReceiver; public StatsCompanionService(Context context) { super(); @@ -75,6 +76,26 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mContext, PollingAlarmReceiver.class), 0); mAppUpdateReceiver = new AppUpdateReceiver(); + mUserUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (sStatsdLock) { + sStatsd = fetchStatsdService(); + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd"); + return; + } + try { + // Pull the latest state of UID->app name, version mapping. + // Needed since the new user basically has a version of every app. + informAllUidsLocked(context); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); + forgetEverything(); + } + } + } + }; Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED."); } @@ -121,6 +142,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { @Override public void onReceive(Context context, Intent intent) { Slog.i(TAG, "StatsCompanionService noticed an app was updated."); + /** + * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid + * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. + */ + if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) && + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + return; // Keep only replacing or normal add and remove. + } synchronized (sStatsdLock) { if (sStatsd == null) { Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); @@ -370,6 +399,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { filter.addDataScheme("package"); mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null, null); + + // Setup receiver for user initialize (which happens once for a new user) and + // if a user is removed. + filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE); + filter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL, + filter, null, null); + // Pull the latest state of UID->app name, version mapping when statsd starts. informAllUidsLocked(mContext); } catch (RemoteException e) { @@ -391,6 +428,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { synchronized (sStatsdLock) { sStatsd = null; mContext.unregisterReceiver(mAppUpdateReceiver); + mContext.unregisterReceiver(mUserUpdateReceiver); cancelAnomalyAlarm(); cancelPollingAlarms(); } diff --git a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java new file mode 100644 index 000000000000..cbe9650edc43 --- /dev/null +++ b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2017 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 distriZenbuted 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 com.android.server.notification; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.media.AudioAttributes; +import android.provider.Settings; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ZenModeHelperTest extends NotificationTestCase { + + @Mock ConditionProviders mConditionProviders; + private TestableLooper mTestableLooper; + private ZenModeHelper mZenModeHelperSpy; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mTestableLooper = TestableLooper.get(this); + mZenModeHelperSpy = spy(new ZenModeHelper(getContext(), mTestableLooper.getLooper(), + mConditionProviders)); + } + + @Test + public void testZenOff_NoMuteApplied() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF; + assertTrue(mZenModeHelperSpy.mConfig.allowAlarms); + mZenModeHelperSpy.applyRestrictions(); + + doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt()); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ALARM); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_MEDIA); + } + + @Test + public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + assertTrue(mZenModeHelperSpy.mConfig.allowAlarms); + assertTrue(mZenModeHelperSpy.mConfig.allowMediaSystemOther); + mZenModeHelperSpy.applyRestrictions(); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ALARM); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_MEDIA); + } + + @Test + public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() { + + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowAlarms = false; + mZenModeHelperSpy.mConfig.allowMediaSystemOther = false; + assertFalse(mZenModeHelperSpy.mConfig.allowAlarms); + assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther); + mZenModeHelperSpy.applyRestrictions(); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_ALARM); + + // Media is a catch-all that includes games and system sounds + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_MEDIA); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_GAME); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION); + } +} diff --git a/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml b/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml new file mode 100644 index 000000000000..266ab99cdf20 --- /dev/null +++ b/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<user> + <launcher-pins package-name="com.android.launcher.1" launcher-user="0"> + <package-info version="9" last_udpate_time="1230768000000"> + <signature hash="0X8l7PvMeFf3vr6kaTCL4LJYCUPpbROjrZihNnXEv8I" /> + </package-info> + <package package-name="com.android.test.1" package-user="0"> + <pin value="s1" /> + </package> + </launcher-pins> + <package name="com.android.test.1" call-count="0" last-reset="1506991428317"> + <package-info version="8" last_udpate_time="1506534668998"> + <signature hash="zDmdc5A/Bu5pQDKrBTjwVjT/fhzl6OUKwzCocUhPNM8" /> + </package-info> + <shortcut id="s1" activity="com.android.test.1/com.example.android.shortcutsample.Main" title="Leak wakelock" titleid="0" textid="0" dmessageid="0" timestamp="1507674156622" flags="130"> + <intent intent-base="#Intent;action=com.example.android.shortcutsample.LEAK;launchFlags=0x1000c000;component=com.example.android.shortcutsample/.Main;end" /> + </shortcut> + </package> +</user> diff --git a/services/tests/servicestests/res/xml/shortcut_5_altalt.xml b/services/tests/servicestests/res/xml/shortcut_5_altalt.xml new file mode 100644 index 000000000000..1476a2739bd9 --- /dev/null +++ b/services/tests/servicestests/res/xml/shortcut_5_altalt.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> +<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" > + <shortcut + android:shortcutId="ms1" + android:enabled="true" + android:icon="@drawable/icon1" + android:shortcutShortLabel="@string/shortcut_title1" + android:shortcutLongLabel="@string/shortcut_text1" + android:shortcutDisabledMessage="@string/shortcut_disabled_message1" + > + <intent + android:action="action1" + android:data="http://a.b.c/1" + > + </intent> + <categories android:name="android.shortcut.conversation" /> + <categories android:name="android.shortcut.media" /> + </shortcut> + <shortcut + android:shortcutId="ms2" + android:enabled="true" + android:icon="@drawable/icon2" + android:shortcutShortLabel="@string/shortcut_title2" + android:shortcutLongLabel="@string/shortcut_text2" + android:shortcutDisabledMessage="@string/shortcut_disabled_message2" + > + <intent + android:action="action2" + > + </intent> + <categories android:name="android.shortcut.conversation" /> + </shortcut> + <shortcut + android:shortcutId="ms3" + android:shortcutShortLabel="@string/shortcut_title1" + android:shortcutLongLabel="@string/shortcut_title2" + > + <intent + android:action="android.intent.action.VIEW" + > + </intent> + </shortcut> + <shortcut + android:shortcutId="ms4" + android:shortcutShortLabel="@string/shortcut_title2" + android:shortcutLongLabel="@string/shortcut_title2" + > + <intent + android:action="android.intent.action.VIEW2" + > + </intent> + <categories /> + <categories android:name="" /> + <categories android:name="cat" /> + </shortcut> + <shortcut + android:shortcutId="ms5" + android:shortcutShortLabel="@string/shortcut_title1" + > + <intent + android:action="action" + android:data="http://www/" + android:targetPackage="abc" + android:targetClass=".xyz" + android:mimeType="foo/bar" + > + <categories android:name="cat1" /> + <categories android:name="cat2" /> + <extra android:name="key1" android:value="value1" /> + <extra android:name="key2" android:value="value2" /> + </intent> + </shortcut> +</shortcuts> diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java index 02f645a07a5f..c8dc9ff51a1b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java @@ -77,7 +77,6 @@ public class AccessibilityCacheTest { mAccessibilityCache.clear(); AccessibilityInteractionClient.getInstance().clearCache(); assertEquals(0, numA11yWinInfosInUse.get()); - assertEquals(0, numA11yNodeInfosInUse.get()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 951f226676b0..d01797644560 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -15,6 +15,11 @@ */ package com.android.server.pm; +import static android.content.pm.ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED; +import static android.content.pm.ShortcutInfo.DISABLED_REASON_NOT_DISABLED; +import static android.content.pm.ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; +import static android.content.pm.ShortcutInfo.DISABLED_REASON_VERSION_LOWER; + import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled; @@ -71,7 +76,9 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherApps; +import android.content.pm.LauncherApps.PinItemRequest; import android.content.pm.LauncherApps.ShortcutQuery; +import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; @@ -101,7 +108,6 @@ import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.function.BiConsumer; -import java.util.function.BiPredicate; /** * Tests for ShortcutService and ShortcutManager. @@ -250,7 +256,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); final Icon icon3 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource( - getTestContext().getResources(), R.drawable.icon2)); + getTestContext().getResources(), R.drawable.icon2)); final ShortcutInfo si1 = makeShortcut( "shortcut1", @@ -706,13 +712,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertBitmapSize(128, 128, bmp); Drawable dr = mLauncherApps.getShortcutIconDrawable( - makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); + makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); assertTrue(dr instanceof AdaptiveIconDrawable); float viewportPercentage = 1 / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction()); assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), - dr.getIntrinsicWidth()); + dr.getIntrinsicWidth()); assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), - dr.getIntrinsicHeight()); + dr.getIntrinsicHeight()); } public void testCleanupDanglingBitmaps() throws Exception { @@ -1118,8 +1124,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Set resource icon assertTrue(mManager.updateShortcuts(list( new ShortcutInfo.Builder(mClientContext, "s1") - .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32)) - .build() + .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32)) + .build() ))); assertWith(getCallerShortcuts()) @@ -1131,9 +1137,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Set bitmap icon assertTrue(mManager.updateShortcuts(list( new ShortcutInfo.Builder(mClientContext, "s1") - .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource( - getTestContext().getResources(), R.drawable.black_64x64))) - .build() + .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource( + getTestContext().getResources(), R.drawable.black_64x64))) + .build() ))); assertWith(getCallerShortcuts()) @@ -2126,7 +2132,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutQuery q = new ShortcutQuery().setQueryFlags( ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_PINNED - | ShortcutQuery.FLAG_MATCH_MANIFEST); + | ShortcutQuery.FLAG_MATCH_MANIFEST); // No shortcuts are visible. assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty(); @@ -2668,10 +2674,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "Title 1", makeComponent(ShortcutActivity.class), /* icon =*/ null, - new Intent[] {makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, + new Intent[]{makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)) .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK), - new Intent("act2").setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)}, + new Intent("act2").setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)}, /* rank */ 10); final ShortcutInfo s1_2 = makeShortcut( @@ -2776,8 +2782,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Not launchable. doReturn(ActivityManager.START_CLASS_NOT_FOUND) .when(mMockActivityManagerInternal).startActivitiesAsPackage( - anyStringOrNull(), anyInt(), - anyOrNull(Intent[].class), anyOrNull(Bundle.class)); + anyStringOrNull(), anyInt(), + anyOrNull(Intent[].class), anyOrNull(Bundle.class)); assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0, ActivityNotFoundException.class); @@ -2911,7 +2917,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectByIds("s1", "s2") .areAllDynamic() - ; + ; }); // 3 Update the app with no manifest shortcuts. (Pinned one will survive.) @@ -3309,13 +3315,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); - final SparseArray<ShortcutUser> users = mService.getShortcutsForTest(); + final SparseArray<ShortcutUser> users = mService.getShortcutsForTest(); assertEquals(2, users.size()); assertEquals(USER_0, users.keyAt(0)); assertEquals(USER_10, users.keyAt(1)); - final ShortcutUser user0 = users.get(USER_0); - final ShortcutUser user10 = users.get(USER_10); + final ShortcutUser user0 = users.get(USER_0); + final ShortcutUser user10 = users.get(USER_10); // Check the registered packages. @@ -3531,7 +3537,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -3548,7 +3554,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -3853,52 +3859,77 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10)); } - protected void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi, - int version, String... signatures) { - assertEquals(expected, spi.canRestoreTo(mService, genPackage( - "dummy", /* uid */ 0, version, signatures))); + protected void checkCanRestoreTo(int expected, ShortcutPackageInfo spi, + boolean anyVersionOk, int version, boolean nowBackupAllowed, String... signatures) { + final PackageInfo pi = genPackage("dummy", /* uid */ 0, version, signatures); + if (!nowBackupAllowed) { + pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP; + } + assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk)); } public void testCanRestoreTo() { addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1"); - addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2"); + addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 10, "sig1", "sig2"); + addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 10, "sig1"); + + updatePackageInfo(CALLING_PACKAGE_3, + pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackageForTest( mService, CALLING_PACKAGE_1, USER_0); final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackageForTest( mService, CALLING_PACKAGE_2, USER_0); - - checkCanRestoreTo(true, spi1, 10, "sig1"); - checkCanRestoreTo(true, spi1, 10, "x", "sig1"); - checkCanRestoreTo(true, spi1, 10, "sig1", "y"); - checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y"); - checkCanRestoreTo(true, spi1, 11, "sig1"); - - checkCanRestoreTo(false, spi1, 10 /* empty */); - checkCanRestoreTo(false, spi1, 10, "x"); - checkCanRestoreTo(false, spi1, 10, "x", "y"); - checkCanRestoreTo(false, spi1, 10, "x"); - checkCanRestoreTo(false, spi1, 9, "sig1"); - - checkCanRestoreTo(true, spi2, 10, "sig1", "sig2"); - checkCanRestoreTo(true, spi2, 10, "sig2", "sig1"); - checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2"); - checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1"); - checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y"); - checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y"); - checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y"); - checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y"); - checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y"); - - checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x"); - checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x"); - checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2"); - checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1"); - checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y"); - checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y"); - checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y"); - checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y"); - checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y"); + final ShortcutPackageInfo spi3 = ShortcutPackageInfo.generateForInstalledPackageForTest( + mService, CALLING_PACKAGE_3, USER_0); + + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "sig1"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "x", "sig1"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "sig1", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "x", "sig1", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 11, true, "sig1"); + + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true/* empty */); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x", "y"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x"); + checkCanRestoreTo(DISABLED_REASON_VERSION_LOWER, spi1, false, 9, true, "sig1"); + + // Any version okay. + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1"); + + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig1", "sig2"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig2", "sig1"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig1", "sig2"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig2", "sig1"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig1", "sig2", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig2", "sig1", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig1", "sig2", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig2", "sig1", "y"); + checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 11, true, "x", "sig2", "sig1", "y"); + + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "sig1", "sig2x"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "sig2", "sig1x"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "x", "sig1x", "sig2"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "x", "sig2x", "sig1"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "sig1", "sig2x", "y"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "sig2", "sig1x", "y"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "x", "sig1x", "sig2", "y"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 10, true, "x", "sig2x", "sig1", "y"); + checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, + spi2, false, 11, true, "x", "sig2x", "sig1", "y"); + + checkCanRestoreTo(DISABLED_REASON_BACKUP_NOT_SUPPORTED, spi1, true, 10, false, "sig1"); + checkCanRestoreTo(DISABLED_REASON_BACKUP_NOT_SUPPORTED, spi3, true, 10, true, "sig1"); } public void testHandlePackageDelete() { @@ -3929,7 +3960,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_1); updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerShortcuts()) @@ -4080,7 +4111,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDataClear(CALLING_PACKAGE_1, USER_0)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4099,7 +4130,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, true); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageDataClear(CALLING_PACKAGE_2, USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4126,7 +4157,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4389,7 +4420,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Update the package. updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -4524,7 +4555,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mRunningUsers.put(USER_10, true); updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageAddIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4552,11 +4583,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectByIds("ms1-alt", "s2") .areAllWithActivity(ACTIVITY2) - ; + ; }); // First, no changes. - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4579,7 +4610,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Disable activity 1 mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4599,7 +4630,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Re-enable activity 1. // Manifest shortcuts will be re-published, but dynamic ones are not. mEnabledActivityChecker = (activity, userId) -> true; - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4617,13 +4648,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectByIds("ms1-alt", "s2") .areAllWithActivity(ACTIVITY2) - ; + ; }); // Disable activity 2 // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled. mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageChangedIntent(CALLING_PACKAGE_1, USER_10)); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -4686,7 +4717,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setCaller(LAUNCHER_1, USER_0); assertForLauncherCallback(mLauncherApps, () -> { updatePackageVersion(CALLING_PACKAGE_1, 1); - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0)); }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0) // Make sure the launcher gets callbacks. @@ -4708,12 +4739,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllNotDynamic() .areAllDisabled() .areAllPinned() - ; + ; }); } protected void prepareForBackupTest() { - prepareCrossProfileDataSet(); backupAndRestore(); @@ -4749,66 +4779,45 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertFileExistsWithContent("user-0/shortcut_dump/restore-4.txt"); assertFileExistsWithContent("user-0/shortcut_dump/restore-5-finish.txt"); - checkBackupAndRestore_success(); + checkBackupAndRestore_success(/*firstRestore=*/ true); } public void testBackupAndRestore_backupRestoreTwice() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - dumpsysOnLogcat("Before second backup"); + checkBackupAndRestore_success(/*firstRestore=*/ true); - backupAndRestore(); - - dumpsysOnLogcat("After second backup"); - - checkBackupAndRestore_success(); - } - - public void testBackupAndRestore_backupRestoreMultiple() { - prepareForBackupTest(); + // Run a backup&restore again. Note the shortcuts that weren't restored in the previous + // restore are disabled, so they won't be restored again. + dumpsysOnLogcat("Before second backup&restore"); - // Note doing a backup & restore again here shouldn't affect the result. backupAndRestore(); - // This also shouldn't affect the result. - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertTrue(mManager.setDynamicShortcuts(list( - makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"), - makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6")))); - }); - - backupAndRestore(); + dumpsysOnLogcat("After second backup&restore"); - checkBackupAndRestore_success(); + checkBackupAndRestore_success(/*firstRestore=*/ false); } public void testBackupAndRestore_restoreToNewVersion() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2); addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5); - checkBackupAndRestore_success(); + checkBackupAndRestore_success(/*firstRestore=*/ true); } public void testBackupAndRestore_restoreToSuperSetSignatures() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - // Change package signatures. addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1); addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy"); - checkBackupAndRestore_success(); + checkBackupAndRestore_success(/*firstRestore=*/ true); } - protected void checkBackupAndRestore_success() { + protected void checkBackupAndRestore_success(boolean firstRestore) { // Make sure non-system user is not restored. final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0); assertEquals(0, userP0.getAllPackagesForTest().size()); @@ -4818,12 +4827,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); + + assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertExistsAndShadow(user0.getAllLaunchersForTest().get( PackageWithUser.of(USER_0, LAUNCHER_1))); assertExistsAndShadow(user0.getAllLaunchersForTest().get( PackageWithUser.of(USER_0, LAUNCHER_2))); - assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1))); @@ -4835,14 +4845,16 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectPinned() - .haveIds("s1", "s2"); + .haveIds("s1", "s2") + .areAllEnabled(); }); installPackage(USER_0, LAUNCHER_1); runWithCaller(LAUNCHER_1, USER_0, () -> { assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) .areAllPinned() - .haveIds("s1"); + .haveIds("s1") + .areAllEnabled(); assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) .isEmpty(); @@ -4862,17 +4874,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectPinned() - .haveIds("s1", "s2", "s3"); + .haveIds("s1", "s2", "s3") + .areAllEnabled(); }); runWithCaller(LAUNCHER_1, USER_0, () -> { assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) .areAllPinned() - .haveIds("s1"); + .haveIds("s1") + .areAllEnabled(); assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) .areAllPinned() - .haveIds("s1", "s2"); + .haveIds("s1", "s2") + .areAllEnabled(); assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) .isEmpty(); @@ -4910,14 +4925,28 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(LAUNCHER_2, USER_0, () -> { assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) .areAllPinned() - .haveIds("s2"); + .haveIds("s2") + .areAllEnabled(); assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) .areAllPinned() - .haveIds("s2", "s3"); + .haveIds("s2", "s3") + .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - .isEmpty(); + if (firstRestore) { + assertWith( + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .haveIds("s2", "s3", "s4") + .areAllDisabled() + .areAllPinned() + .areAllNotDynamic() + .areAllWithDisabledReason( + ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); + } else { + assertWith( + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); + } assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) .isEmpty(); @@ -4937,14 +4966,27 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(LAUNCHER_1, USER_0, () -> { assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) .areAllPinned() - .haveIds("s1"); + .haveIds("s1") + .areAllEnabled(); assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) .areAllPinned() - .haveIds("s1", "s2"); + .haveIds("s1", "s2") + .areAllEnabled(); - assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - .isEmpty(); + if (firstRestore) { + assertWith( + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .haveIds("s1", "s2", "s3") + .areAllDisabled() + .areAllPinned() + .areAllNotDynamic() + .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); + } else { + assertWith( + mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); + } assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0)) .isEmpty(); @@ -4954,45 +4996,39 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertWith(getCallerVisibleShortcuts()) .areAllPinned() - .haveIds("s1", "s2", "s3"); + .haveIds("s1", "s2", "s3") + .areAllEnabled(); }); } public void testBackupAndRestore_publisherLowerVersion() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version - checkBackupAndRestore_publisherNotRestored(); + checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_VERSION_LOWER); } public void testBackupAndRestore_publisherWrongSignature() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature - checkBackupAndRestore_publisherNotRestored(); + checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH); } public void testBackupAndRestore_publisherNoLongerBackupTarget() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - updatePackageInfo(CALLING_PACKAGE_1, pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); - checkBackupAndRestore_publisherNotRestored(); + checkBackupAndRestore_publisherNotRestored( + ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); } - protected void checkBackupAndRestore_publisherNotRestored() { + protected void checkBackupAndRestore_publisherNotRestored( + int package1DisabledReason) { installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); @@ -5014,27 +5050,31 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { installPackage(USER_0, LAUNCHER_1); runWithCaller(LAUNCHER_1, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s1", "s2"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .haveIds("s1") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(package1DisabledReason); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .haveIds("s1", "s2") + .areAllPinned() + .areAllEnabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); }); installPackage(USER_0, LAUNCHER_2); runWithCaller(LAUNCHER_2, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s2", "s3"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .haveIds("s2") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(package1DisabledReason); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .haveIds("s2", "s3") + .areAllPinned() + .areAllEnabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); }); installPackage(USER_0, CALLING_PACKAGE_3); @@ -5044,46 +5084,51 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); runWithCaller(LAUNCHER_1, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s1", "s2"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .haveIds("s1") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(package1DisabledReason); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .haveIds("s1", "s2") + .areAllPinned() + .areAllEnabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .haveIds("s1", "s2", "s3") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); }); runWithCaller(LAUNCHER_2, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s2", "s3"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .haveIds("s2") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(package1DisabledReason); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .haveIds("s2", "s3") + .areAllPinned() + .areAllEnabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .haveIds("s2", "s3", "s4") + .areAllPinned() + .areAllDisabled() + .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); }); } public void testBackupAndRestore_launcherLowerVersion() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version - checkBackupAndRestore_launcherNotRestored(); + // Note, we restore pinned shortcuts even if the launcher is of a lower version. + checkBackupAndRestore_success(/*firstRestore=*/ true); } public void testBackupAndRestore_launcherWrongSignature() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature checkBackupAndRestore_launcherNotRestored(); @@ -5092,9 +5137,6 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void testBackupAndRestore_launcherNoLongerBackupTarget() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - updatePackageInfo(LAUNCHER_1, pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); @@ -5185,18 +5227,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(assertAllPinned( mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), "s2", "s3"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); }); } public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() { prepareForBackupTest(); - // Note doing a backup & restore again here shouldn't affect the result. - backupAndRestore(); - updatePackageInfo(CALLING_PACKAGE_1, pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); @@ -5235,15 +5271,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); installPackage(USER_0, LAUNCHER_2); runWithCaller(LAUNCHER_2, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s2", "s3"); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2") + .areAllDisabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2", "s3"); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) + .isEmpty(); }); // Because launcher 1 wasn't restored, "s1" is no longer pinned. @@ -5272,15 +5308,21 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* empty */); }); runWithCaller(LAUNCHER_2, USER_0, () -> { - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) - /* empty */); - assertShortcutIds(assertAllPinned( - mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)), - "s2", "s3"); - assertShortcutIds(assertAllPinned( + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2") + .areAllDisabled(); + assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)) + .areAllPinned() + .haveIds("s2", "s3"); + assertWith( mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0)) - /* empty */); + .haveIds("s2", "s3", "s4") + .areAllDisabled() + .areAllPinned() + .areAllNotDynamic() + .areAllWithDisabledReason( + ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED); }); } @@ -5305,12 +5347,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1)); assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2)); + assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertExistsAndShadow(user0.getAllLaunchersForTest().get( PackageWithUser.of(USER_0, LAUNCHER_1))); assertExistsAndShadow(user0.getAllLaunchersForTest().get( PackageWithUser.of(USER_0, LAUNCHER_2))); - assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3)); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1))); @@ -5421,7 +5463,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .revertToOriginalList() .selectByIds("s1", "s2") .areAllNotDynamic() - ; + ; }); } @@ -5555,6 +5597,287 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); } + + /** + * Restored to a lower version with no manifest shortcuts. All shortcuts are now invisible, + * and all calls from the publisher should ignore them. + */ + public void testBackupAndRestore_disabledShortcutsAreIgnored() { + // Publish two manifest shortcuts. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_5_altalt); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertTrue(mManager.setDynamicShortcuts(list( + makeShortcutWithShortLabel("s1", "original-title"), + makeShortcut("s2"), makeShortcut("s3")))); + }); + + // Pin from launcher 1. + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, + list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0); + }); + + backupAndRestore(); + + // Lower the version and remove the manifest shortcuts. + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_0); + addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version + + // When re-installing the app, the manifest shortcut should be re-published. + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + mService.mPackageMonitor.onReceive(mServiceContext, + genPackageAddIntent(LAUNCHER_1, USER_0)); + + // No shortcuts should be visible to the publisher. + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerVisibleShortcuts()) + .isEmpty(); + }); + + final Runnable checkAllDisabledForLauncher = () -> { + runWithCaller(LAUNCHER_1, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .areAllPinned() + .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2") + .areAllDisabled() + .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_VERSION_LOWER) + + .forShortcutWithId("s1", si -> { + assertEquals("original-title", si.getShortLabel()); + }) + .forShortcutWithId("ms1", si -> { + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title1 + "/en" + , si.getShortLabel()); + }) + .forShortcutWithId("ms2", si -> { + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title2 + "/en" + , si.getShortLabel()); + }) + .forShortcutWithId("ms3", si -> { + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title1 + "/en" + , si.getShortLabel()); + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title2 + "/en" + , si.getLongLabel()); + }) + .forShortcutWithId("ms4", si -> { + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title2 + "/en" + , si.getShortLabel()); + assertEquals("string-com.android.test.1-user:0-res:" + + R.string.shortcut_title2 + "/en" + , si.getLongLabel()); + }); + }); + }; + + checkAllDisabledForLauncher.run(); + + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + + makeCallerForeground(); // CALLING_PACKAGE_1 is now in the foreground. + + // All changing API calls should be ignored. + + getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2")); + checkAllDisabledForLauncher.run(); + + getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2")); + checkAllDisabledForLauncher.run(); + + getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2")); + checkAllDisabledForLauncher.run(); + + getManager().removeAllDynamicShortcuts(); + getManager().removeDynamicShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2")); + checkAllDisabledForLauncher.run(); + + getManager().updateShortcuts(list(makeShortcutWithShortLabel("s1", "new-title"))); + checkAllDisabledForLauncher.run(); + + + // Add a shortcut -- even though ms1 was immutable, it will succeed. + assertTrue(getManager().addDynamicShortcuts(list( + makeShortcutWithShortLabel("ms1", "original-title")))); + + runWithCaller(LAUNCHER_1, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2") + + .selectByIds("ms1") + .areAllEnabled() + .areAllDynamic() + .areAllPinned() + .forAllShortcuts(si -> { + assertEquals("original-title", si.getShortLabel()); + }) + + // The rest still exist and disabled. + .revertToOriginalList() + .selectByIds("ms2", "ms3", "ms4", "s1", "s2") + .areAllDisabled() + .areAllPinned() + ; + }); + + assertTrue(getManager().setDynamicShortcuts(list( + makeShortcutWithShortLabel("ms2", "new-title-2")))); + + runWithCaller(LAUNCHER_1, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2") + + .selectByIds("ms1") + .areAllEnabled() + .areAllNotDynamic() // ms1 was not in the list, so no longer dynamic. + .areAllPinned() + .areAllMutable() + .forAllShortcuts(si -> { + assertEquals("original-title", si.getShortLabel()); + }) + + .revertToOriginalList() + .selectByIds("ms2") + .areAllEnabled() + .areAllDynamic() + .areAllPinned() + .areAllMutable() + .forAllShortcuts(si -> { + assertEquals("new-title-2", si.getShortLabel()); + }) + + // The rest still exist and disabled. + .revertToOriginalList() + .selectByIds("ms3", "ms4", "s1", "s2") + .areAllDisabled() + .areAllPinned() + ; + }); + + // Prepare for requestPinShortcut(). + setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0)); + mPinConfirmActivityFetcher = (packageName, userId) -> + new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS); + + mManager.requestPinShortcut( + makeShortcutWithShortLabel("ms3", "new-title-3"), + /*PendingIntent=*/ null); + + // Note this was pinned, so it'll be accepted right away. + runWithCaller(LAUNCHER_1, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .selectByIds("ms3") + .areAllEnabled() + .areAllNotDynamic() + .areAllPinned() + .areAllMutable() + .forAllShortcuts(si -> { + assertEquals("new-title-3", si.getShortLabel()); + // The new one replaces the old manifest shortcut, so the long label + // should be gone now. + assertNull(si.getLongLabel()); + }); + }); + + // Now, change the launcher to launcher2, and request pin again. + setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0)); + + reset(mServiceContext); + + assertTrue(mManager.isRequestPinShortcutSupported()); + mManager.requestPinShortcut( + makeShortcutWithShortLabel("ms4", "new-title-4"), + /*PendingIntent=*/ null); + + // Initially there should be no pinned shortcuts for L2. + runWithCaller(LAUNCHER_2, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .selectPinned() + .isEmpty(); + + final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); + + verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0)); + + assertEquals(LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT, + intent.getValue().getAction()); + assertEquals(LAUNCHER_2, intent.getValue().getComponent().getPackageName()); + + // Check the request object. + final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue()); + + assertNotNull(request); + assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType()); + + assertWith(request.getShortcutInfo()) + .haveIds("ms4") + .areAllOrphan() + .forAllShortcuts(si -> { + assertEquals("new-title-4", si.getShortLabel()); + // The new one replaces the old manifest shortcut, so the long label + // should be gone now. + assertNull(si.getLongLabel()); + }); + assertTrue(request.accept()); + + assertWith(getShortcutAsLauncher(USER_0)) + .selectPinned() + .haveIds("ms4") + .areAllEnabled(); + }); + }); + } + + /** + * Test for restoring the pre-P backup format. + */ + public void testBackupAndRestore_api27format() throws Exception { + final byte[] payload = readTestAsset("shortcut/shortcut_api27_backup.xml").getBytes(); + + addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "22222"); + addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "11111"); + + runWithSystemUid(() -> mService.applyRestore(payload, USER_0)); + + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertWith(getCallerShortcuts()) + .areAllPinned() + .haveIds("s1") + .areAllEnabled(); + }); + + runWithCaller(LAUNCHER_1, USER_0, () -> { + assertWith(getShortcutAsLauncher(USER_0)) + .areAllPinned() + .haveIds("s1") + .areAllEnabled(); + }); + // Make sure getBackupSourceVersionCode and isBackupSourceBackupAllowed + // are correct. We didn't have them in the old format. + assertEquals(8, mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + .getPackageInfo().getBackupSourceVersionCode()); + assertTrue(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) + .getPackageInfo().isBackupSourceBackupAllowed()); + + assertEquals(9, mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0) + .getPackageInfo().getBackupSourceVersionCode()); + assertTrue(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0) + .getPackageInfo().isBackupSourceBackupAllowed()); + + } + public void testSaveAndLoad_crossProfile() { prepareCrossProfileDataSet(); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 3220ea960f5d..fcdadaccd2ac 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -1131,7 +1131,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, si.getRank()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED + | ShortcutInfo.FLAG_SHADOW , si.getFlags()); assertNull(si.getBitmapPath()); // No icon. assertEquals(0, si.getIconResourceId()); @@ -1198,7 +1199,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, si.getRank()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED + | ShortcutInfo.FLAG_SHADOW , si.getFlags()); assertNull(si.getBitmapPath()); // No icon. assertEquals(0, si.getIconResourceId()); assertEquals(null, si.getIconResName()); diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java index 926a606df294..a4349f45a897 100644 --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java +++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertNotEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyList; import static org.mockito.Matchers.anyString; @@ -59,9 +60,7 @@ import org.hamcrest.Matcher; import org.json.JSONException; import org.json.JSONObject; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; import org.mockito.hamcrest.MockitoHamcrest; import java.io.BufferedReader; @@ -898,11 +897,14 @@ public class ShortcutManagerTestUtils { public ShortcutListAsserter areAllEnabled() { forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isEnabled())); + areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); return this; } public ShortcutListAsserter areAllDisabled() { forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isEnabled())); + forAllShortcuts(s -> assertNotEquals("id=" + s.getId(), + ShortcutInfo.DISABLED_REASON_NOT_DISABLED, s.getDisabledReason())); return this; } @@ -930,6 +932,16 @@ public class ShortcutManagerTestUtils { return this; } + public ShortcutListAsserter areAllVisibleToPublisher() { + forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isVisibleToPublisher())); + return this; + } + + public ShortcutListAsserter areAllNotVisibleToPublisher() { + forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isVisibleToPublisher())); + return this; + } + public ShortcutListAsserter areAllWithKeyFieldsOnly() { forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.hasKeyFieldsOnly())); return this; @@ -960,6 +972,17 @@ public class ShortcutManagerTestUtils { return this; } + public ShortcutListAsserter areAllWithDisabledReason(int disabledReason) { + forAllShortcuts(s -> assertEquals("id=" + s.getId(), + disabledReason, s.getDisabledReason())); + if (disabledReason == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + areAllVisibleToPublisher(); + } else { + areAllNotVisibleToPublisher(); + } + return this; + } + public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) { boolean found = false; for (int i = 0; i < mList.size(); i++) { diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java index 764b7b22f3d2..9a9877a88517 100644 --- a/telephony/java/android/telephony/MbmsDownloadSession.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -77,8 +77,9 @@ public class MbmsDownloadSession implements AutoCloseable { * Integer extra that Android will attach to the intent supplied via * {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)} * Indicates the result code of the download. One of - * {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, {@link #RESULT_CANCELLED}, or - * {@link #RESULT_IO_ERROR}. + * {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, {@link #RESULT_CANCELLED}, + * {@link #RESULT_IO_ERROR}, {@link #RESULT_DOWNLOAD_FAILURE}, {@link #RESULT_OUT_OF_STORAGE}, + * {@link #RESULT_SERVICE_ID_NOT_DEFINED}, or {@link #RESULT_FILE_ROOT_UNREACHABLE}. * * This extra may also be used by the middleware when it is sending intents to the app. */ @@ -142,11 +143,41 @@ public class MbmsDownloadSession implements AutoCloseable { /** * Indicates that the download will not be completed due to an I/O error incurred while - * writing to temp files. This commonly indicates that the device is out of storage space, - * but may indicate other conditions as well (such as an SD card being removed). + * writing to temp files. + * + * This is likely a transient error and another {@link DownloadRequest} should be sent to try + * the download again. */ public static final int RESULT_IO_ERROR = 4; - // TODO - more results! + + /** + * Indicates that the Service ID specified in the {@link DownloadRequest} is incorrect due to + * the Id being incorrect, stale, expired, or similar. + */ + public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; + + /** + * Indicates that there was an error while processing downloaded files, such as a file repair or + * file decoding error and is not due to a file I/O error. + * + * This is likely a transient error and another {@link DownloadRequest} should be sent to try + * the download again. + */ + public static final int RESULT_DOWNLOAD_FAILURE = 6; + + /** + * Indicates that the file system is full and the {@link DownloadRequest} can not complete. + * Either space must be made on the current file system or the temp file root location must be + * changed to a location that is not full to download the temp files. + */ + public static final int RESULT_OUT_OF_STORAGE = 7; + + /** + * Indicates that the file root that was set is currently unreachable. This can happen if the + * temp files are set to be stored on external storage and the SD card was removed, for example. + * The temp file root should be changed before sending another DownloadRequest. + */ + public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; /** @hide */ @Retention(RetentionPolicy.SOURCE) diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java index fe2753722aae..9af1eb9e14d7 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java @@ -287,7 +287,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return; } - List<Uri> tempFiles = intent.getParcelableExtra(VendorUtils.EXTRA_TEMP_LIST); + List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST); if (tempFiles == null) { return; } @@ -309,7 +309,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return; } int fdCount = intent.getIntExtra(VendorUtils.EXTRA_FD_COUNT, 0); - List<Uri> pausedList = intent.getParcelableExtra(VendorUtils.EXTRA_PAUSED_LIST); + List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST); if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) { Log.i(LOG_TAG, "No temp files actually requested. Ending."); @@ -492,9 +492,14 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("Package manager couldn't find " + context.getPackageName()); } + if (appInfo.metaData == null) { + throw new RuntimeException("App must declare the file provider authority as metadata " + + "in the manifest."); + } String authority = appInfo.metaData.getString(MBMS_FILE_PROVIDER_META_DATA_KEY); if (authority == null) { - throw new RuntimeException("Must declare the file provider authority as meta data"); + throw new RuntimeException("App must declare the file provider authority as metadata " + + "in the manifest."); } return authority; } diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java index 9f31d27508b2..ccb0f3b07d0f 100644 --- a/tests/net/java/android/net/IpSecManagerTest.java +++ b/tests/net/java/android/net/IpSecManagerTest.java @@ -31,19 +31,21 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.system.Os; -import android.test.AndroidTestCase; + import com.android.server.IpSecService; + import java.net.InetAddress; import java.net.UnknownHostException; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; /** Unit tests for {@link IpSecManager}. */ @SmallTest -@RunWith(JUnit4.class) +@RunWith(AndroidJUnit4.class) public class IpSecManagerTest { private static final int TEST_UDP_ENCAP_PORT = 34567; diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java index 1cb0ecdba7f3..52da79a18c6e 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/tests/net/java/android/net/LinkPropertiesTest.java @@ -16,19 +16,22 @@ package android.net; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; import android.net.LinkProperties.ProvisioningChange; import android.net.RouteInfo; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.system.OsConstants; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.Suppress; import android.util.ArraySet; -import junit.framework.TestCase; - import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; @@ -37,8 +40,12 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import org.junit.Test; +import org.junit.runner.RunWith; -public class LinkPropertiesTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LinkPropertiesTest { private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); @@ -92,7 +99,7 @@ public class LinkPropertiesTest extends TestCase { assertEquals(source.hashCode(), target.hashCode()); } - @SmallTest + @Test public void testEqualsNull() { LinkProperties source = new LinkProperties(); LinkProperties target = new LinkProperties(); @@ -101,155 +108,141 @@ public class LinkPropertiesTest extends TestCase { assertLinkPropertiesEqual(source, target); } - @SmallTest - public void testEqualsSameOrder() { - try { - LinkProperties source = new LinkProperties(); - source.setInterfaceName(NAME); - // set 2 link addresses - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - // set 2 dnses - source.addDnsServer(DNS1); - source.addDnsServer(DNS2); - // set 2 gateways - source.addRoute(new RouteInfo(GATEWAY1)); - source.addRoute(new RouteInfo(GATEWAY2)); - source.setMtu(MTU); - - LinkProperties target = new LinkProperties(); - - // All fields are same - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - - assertLinkPropertiesEqual(source, target); - - target.clear(); - // change Interface Name - target.setInterfaceName("qmi1"); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - // change link addresses - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - // change dnses - target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - // change gateway - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - // change mtu - target.setMtu(1440); - assertFalse(source.equals(target)); - - } catch (Exception e) { - throw new RuntimeException(e.toString()); - //fail(); - } + @Test + public void testEqualsSameOrder() throws Exception { + LinkProperties source = new LinkProperties(); + source.setInterfaceName(NAME); + // set 2 link addresses + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); + // set 2 dnses + source.addDnsServer(DNS1); + source.addDnsServer(DNS2); + // set 2 gateways + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); + source.setMtu(MTU); + + LinkProperties target = new LinkProperties(); + + // All fields are same + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(DNS1); + target.addDnsServer(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + + assertLinkPropertiesEqual(source, target); + + target.clear(); + // change Interface Name + target.setInterfaceName("qmi1"); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(DNS1); + target.addDnsServer(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + assertFalse(source.equals(target)); + + target.clear(); + target.setInterfaceName(NAME); + // change link addresses + target.addLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(DNS1); + target.addDnsServer(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + assertFalse(source.equals(target)); + + target.clear(); + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + // change dnses + target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); + target.addDnsServer(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + assertFalse(source.equals(target)); + + target.clear(); + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(DNS1); + target.addDnsServer(DNS2); + // change gateway + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + assertFalse(source.equals(target)); + + target.clear(); + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(DNS1); + target.addDnsServer(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + // change mtu + target.setMtu(1440); + assertFalse(source.equals(target)); } - @SmallTest - public void testEqualsDifferentOrder() { - try { - LinkProperties source = new LinkProperties(); - source.setInterfaceName(NAME); - // set 2 link addresses - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - // set 2 dnses - source.addDnsServer(DNS1); - source.addDnsServer(DNS2); - // set 2 gateways - source.addRoute(new RouteInfo(GATEWAY1)); - source.addRoute(new RouteInfo(GATEWAY2)); - source.setMtu(MTU); - - LinkProperties target = new LinkProperties(); - // Exchange order - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV6); - target.addLinkAddress(LINKADDRV4); - target.addDnsServer(DNS2); - target.addDnsServer(DNS1); - target.addRoute(new RouteInfo(GATEWAY2)); - target.addRoute(new RouteInfo(GATEWAY1)); - target.setMtu(MTU); - - assertLinkPropertiesEqual(source, target); - } catch (Exception e) { - fail(); - } + @Test + public void testEqualsDifferentOrder() throws Exception { + LinkProperties source = new LinkProperties(); + source.setInterfaceName(NAME); + // set 2 link addresses + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); + // set 2 dnses + source.addDnsServer(DNS1); + source.addDnsServer(DNS2); + // set 2 gateways + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); + source.setMtu(MTU); + + LinkProperties target = new LinkProperties(); + // Exchange order + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV4); + target.addDnsServer(DNS2); + target.addDnsServer(DNS1); + target.addRoute(new RouteInfo(GATEWAY2)); + target.addRoute(new RouteInfo(GATEWAY1)); + target.setMtu(MTU); + + assertLinkPropertiesEqual(source, target); } - @SmallTest - public void testEqualsDuplicated() { - try { - LinkProperties source = new LinkProperties(); - // set 3 link addresses, eg, [A, A, B] - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - - LinkProperties target = new LinkProperties(); - // set 3 link addresses, eg, [A, B, B] - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addLinkAddress(LINKADDRV6); - - assertLinkPropertiesEqual(source, target); - } catch (Exception e) { - fail(); - } + @Test + public void testEqualsDuplicated() throws Exception { + LinkProperties source = new LinkProperties(); + // set 3 link addresses, eg, [A, A, B] + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); + + LinkProperties target = new LinkProperties(); + // set 3 link addresses, eg, [A, B, B] + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV6); + + assertLinkPropertiesEqual(source, target); } private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) { @@ -258,7 +251,7 @@ public class LinkPropertiesTest extends TestCase { } } - @SmallTest + @Test public void testRouteInterfaces() { LinkAddress prefix = new LinkAddress( NetworkUtils.numericToInetAddress("2001:db8::"), 32); @@ -317,7 +310,7 @@ public class LinkPropertiesTest extends TestCase { assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); } - @SmallTest + @Test public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); @@ -373,7 +366,7 @@ public class LinkPropertiesTest extends TestCase { return lp.getLinkAddresses().iterator().next(); } - @SmallTest + @Test public void testAddressMethods() { LinkProperties lp = new LinkProperties(); @@ -460,7 +453,7 @@ public class LinkPropertiesTest extends TestCase { assertEquals(0, lp.getLinkAddresses().size()); } - @SmallTest + @Test public void testSetLinkAddresses() { LinkProperties lp = new LinkProperties(); lp.addLinkAddress(LINKADDRV4); @@ -475,7 +468,7 @@ public class LinkPropertiesTest extends TestCase { assertTrue(lp.equals(lp)); } - @SmallTest + @Test public void testIsProvisioned() { LinkProperties lp4 = new LinkProperties(); assertFalse("v4only:empty", lp4.isProvisioned()); @@ -529,7 +522,7 @@ public class LinkPropertiesTest extends TestCase { assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned()); } - @SmallTest + @Test public void testCompareProvisioning() { LinkProperties v4lp = new LinkProperties(); v4lp.addLinkAddress(LINKADDRV4); @@ -589,8 +582,7 @@ public class LinkPropertiesTest extends TestCase { LinkProperties.compareProvisioning(v6lp, v6lp2)); } - @SmallTest - @Suppress // Failing. + @Test public void testIsReachable() { final LinkProperties v4lp = new LinkProperties(); assertFalse(v4lp.isReachable(DNS1)); @@ -687,7 +679,7 @@ public class LinkPropertiesTest extends TestCase { assertTrue(v6lp.isReachable(DNS1)); } - @SmallTest + @Test public void testLinkPropertiesEnsureDirectlyConnectedRoutes() { // IPv4 case: no route added initially LinkProperties rmnet0 = new LinkProperties(); @@ -750,25 +742,25 @@ public class LinkPropertiesTest extends TestCase { } - @SmallTest + @Test public void testCompareResult() { // Either adding or removing items - testCompareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1), + compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1), Arrays.asList(2, 3, 4), new ArrayList<>()); - testCompareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4), + compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4), new ArrayList<>(), Arrays.asList(3, 4)); // adding and removing items at the same time - testCompareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5), + compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5), Arrays.asList(1), Arrays.asList(5)); - testCompareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), + compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)); // null cases - testCompareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>()); - testCompareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3)); - testCompareResult(null, null, new ArrayList<>(), new ArrayList<>()); + compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>()); + compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3)); + compareResult(null, null, new ArrayList<>(), new ArrayList<>()); } private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) { @@ -780,7 +772,7 @@ public class LinkPropertiesTest extends TestCase { assertEquals(expectedSet, actualSet); } - private <T> void testCompareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved, + private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved, List<T> expectAdded) { CompareResult<T> result = new CompareResult<>(oldItems, newItems); assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added)); diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index eb85eb445cbc..25289ba92e24 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -30,23 +30,30 @@ import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import com.google.android.collect.Sets; -import junit.framework.TestCase; - import java.util.HashSet; +import org.junit.runner.RunWith; +import org.junit.Test; + +@RunWith(AndroidJUnit4.class) @SmallTest -public class NetworkStatsTest extends TestCase { +public class NetworkStatsTest { private static final String TEST_IFACE = "test0"; private static final String TEST_IFACE2 = "test2"; private static final int TEST_UID = 1001; private static final long TEST_START = 1194220800000L; + @Test public void testFindIndex() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 5) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, @@ -74,6 +81,7 @@ public class NetworkStatsTest extends TestCase { ROAMING_NO)); } + @Test public void testFindIndexHinted() { final NetworkStats stats = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L, @@ -116,6 +124,7 @@ public class NetworkStatsTest extends TestCase { } } + @Test public void testAddEntryGrow() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 4); @@ -168,6 +177,7 @@ public class NetworkStatsTest extends TestCase { ROAMING_YES, 7L, 70L, 5L, 50L, 11); } + @Test public void testCombineExisting() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 10); @@ -190,6 +200,7 @@ public class NetworkStatsTest extends TestCase { 256L, 2L, 256L, 2L, 6); } + @Test public void testSubtractIdenticalData() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) @@ -208,6 +219,7 @@ public class NetworkStatsTest extends TestCase { 0L, 0L, 0L, 0); } + @Test public void testSubtractIdenticalRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) @@ -226,6 +238,7 @@ public class NetworkStatsTest extends TestCase { 1L, 4L, 1L, 8); } + @Test public void testSubtractNewRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) @@ -247,6 +260,7 @@ public class NetworkStatsTest extends TestCase { 1024L, 8L, 1024L, 8L, 20); } + @Test public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) @@ -264,6 +278,7 @@ public class NetworkStatsTest extends TestCase { assertEquals(4L, result.getTotalBytes()); } + @Test public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) @@ -304,6 +319,7 @@ public class NetworkStatsTest extends TestCase { assertEquals(96L, uidRoaming.getTotalBytes()); } + @Test public void testGroupedByIfaceEmpty() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3); final NetworkStats grouped = uidStats.groupedByIface(); @@ -312,6 +328,7 @@ public class NetworkStatsTest extends TestCase { assertEquals(0, grouped.size()); } + @Test public void testGroupedByIfaceAll() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3) .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L, @@ -329,6 +346,7 @@ public class NetworkStatsTest extends TestCase { 384L, 24L, 0L, 6L, 0L); } + @Test public void testGroupedByIface() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 7) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, @@ -357,6 +375,7 @@ public class NetworkStatsTest extends TestCase { 1024L, 64L, 0L, 0L, 0L); } + @Test public void testAddAllValues() { final NetworkStats first = new NetworkStats(TEST_START, 5) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L, @@ -387,6 +406,7 @@ public class NetworkStatsTest extends TestCase { 32L, 0L, 0L, 0L, 0L); } + @Test public void testGetTotal() { final NetworkStats stats = new NetworkStats(TEST_START, 7) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, @@ -415,6 +435,7 @@ public class NetworkStatsTest extends TestCase { assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L); } + @Test public void testWithoutUid() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) @@ -433,6 +454,7 @@ public class NetworkStatsTest extends TestCase { 8L, 0L, 0L, 0L); } + @Test public void testClone() throws Exception { final NetworkStats original = new NetworkStats(TEST_START, 5) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) @@ -449,6 +471,7 @@ public class NetworkStatsTest extends TestCase { assertEquals(128L + 512L, clone.getTotalBytes()); } + @Test public void testAddWhenEmpty() throws Exception { final NetworkStats red = new NetworkStats(TEST_START, -1); final NetworkStats blue = new NetworkStats(TEST_START, 5) @@ -459,6 +482,7 @@ public class NetworkStatsTest extends TestCase { red.combineAllValues(blue); } + @Test public void testMigrateTun() throws Exception { final int tunUid = 10030; final String tunIface = "tun0"; @@ -556,6 +580,7 @@ public class NetworkStatsTest extends TestCase { // interface by the vpn app before it's sent out of the underlying interface. The VPN app should // not be charged for the echoed data but it should still be charged for any extra data it sends // via the underlying interface. + @Test public void testMigrateTun_VpnAsLoopback() { final int tunUid = 10030; final String tunIface = "tun0"; diff --git a/core/tests/coretests/src/android/net/NetworkTest.java b/tests/net/java/android/net/NetworkTest.java index 74b6d982b0dc..bacf986b3627 100644 --- a/core/tests/coretests/src/android/net/NetworkTest.java +++ b/tests/net/java/android/net/NetworkTest.java @@ -16,13 +16,17 @@ package android.net; -import static android.test.MoreAsserts.assertNotEqual; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.Network; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import java.io.File; import java.io.FileDescriptor; @@ -32,13 +36,17 @@ import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Inet6Address; import java.net.SocketException; +import java.util.Objects; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; -public class NetworkTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetworkTest { final Network mNetwork = new Network(99); - @SmallTest + @Test public void testBindSocketOfInvalidFdThrows() throws Exception { final FileDescriptor fd = new FileDescriptor(); @@ -50,7 +58,7 @@ public class NetworkTest extends TestCase { } catch (SocketException expected) {} } - @SmallTest + @Test public void testBindSocketOfNonSocketFdThrows() throws Exception { final File devNull = new File("/dev/null"); assertTrue(devNull.canRead()); @@ -65,7 +73,7 @@ public class NetworkTest extends TestCase { } catch (SocketException expected) {} } - @SmallTest + @Test public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception { final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY); mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53); @@ -77,7 +85,7 @@ public class NetworkTest extends TestCase { } catch (SocketException expected) {} } - @SmallTest + @Test public void testBindSocketOfLocalSocketThrows() throws Exception { final LocalSocket mLocalClient = new LocalSocket(); mLocalClient.bind(new LocalSocketAddress("testClient")); @@ -98,7 +106,7 @@ public class NetworkTest extends TestCase { } catch (SocketException expected) {} } - @SmallTest + @Test public void testZeroIsObviousForDebugging() { Network zero = new Network(0); assertEquals(0, zero.hashCode()); @@ -106,7 +114,7 @@ public class NetworkTest extends TestCase { assertEquals("0", zero.toString()); } - @SmallTest + @Test public void testGetNetworkHandle() { Network one = new Network(1); Network two = new Network(2); @@ -143,4 +151,8 @@ public class NetworkTest extends TestCase { assertEquals(8606370526L, two.getNetworkHandle()); assertEquals(12901337822L, three.getNetworkHandle()); } + + private static <T> void assertNotEqual(T t1, T t2) { + assertFalse(Objects.equals(t1, t2)); + } } diff --git a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java index 59f780fefb8b..5bb573455358 100644 --- a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java +++ b/tests/net/java/android/net/StaticIpConfigurationTest.java @@ -16,22 +16,26 @@ package android.net; -import android.net.IpPrefix; -import android.net.LinkAddress; -import android.net.RouteInfo; -import android.net.StaticIpConfiguration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import android.os.Parcel; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import java.net.InetAddress; import java.util.HashSet; +import java.util.Objects; -import junit.framework.TestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.runner.RunWith; - -public class StaticIpConfigurationTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StaticIpConfigurationTest { private static final String ADDRSTR = "192.0.2.2/25"; private static final LinkAddress ADDR = new LinkAddress(ADDRSTR); @@ -53,16 +57,8 @@ public class StaticIpConfigurationTest extends TestCase { assertEquals(0, s.dnsServers.size()); } - private boolean isEqual(StaticIpConfiguration s1, StaticIpConfiguration s2) { - return s1.equals(s2); - } - - private void assertEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) { - assertTrue(isEqual(s1, s2)); - } - - private void assertNotEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) { - assertFalse(isEqual(s1, s2)); + private static <T> void assertNotEquals(T t1, T t2) { + assertFalse(Objects.equals(t1, t2)); } private StaticIpConfiguration makeTestObject() { @@ -76,13 +72,13 @@ public class StaticIpConfigurationTest extends TestCase { return s; } - @SmallTest + @Test public void testConstructor() { StaticIpConfiguration s = new StaticIpConfiguration(); checkEmpty(s); } - @SmallTest + @Test public void testCopyAndClear() { StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null); checkEmpty(empty); @@ -94,7 +90,7 @@ public class StaticIpConfigurationTest extends TestCase { assertEquals(empty, s2); } - @SmallTest + @Test public void testHashCodeAndEquals() { HashSet<Integer> hashCodes = new HashSet(); hashCodes.add(0); @@ -143,7 +139,7 @@ public class StaticIpConfigurationTest extends TestCase { assertNotEquals(s, s2); } - @SmallTest + @Test public void testToLinkProperties() { LinkProperties expected = new LinkProperties(); expected.setInterfaceName(IFACE); @@ -215,11 +211,10 @@ public class StaticIpConfigurationTest extends TestCase { return s2; } - @SmallTest + @Test public void testParceling() { StaticIpConfiguration s = makeTestObject(); StaticIpConfiguration s2 = passThroughParcel(s); assertEquals(s, s2); } } - diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java index 0a56e1be6cae..1d1013e79219 100644 --- a/tests/net/java/android/net/UidRangeTest.java +++ b/tests/net/java/android/net/UidRangeTest.java @@ -16,14 +16,20 @@ package android.net; -import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; -import junit.framework.TestCase; +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; -import static org.junit.Assert.assertArrayEquals; +import org.junit.runner.RunWith; +import org.junit.Test; -public class UidRangeTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UidRangeTest { static { System.loadLibrary("frameworksnettestsjni"); @@ -33,7 +39,7 @@ public class UidRangeTest extends TestCase { private static native int getStart(byte[] inParcel); private static native int getStop(byte[] inParcel); - @SmallTest + @Test public void testNativeParcelUnparcel() { UidRange original = new UidRange(1234, Integer.MAX_VALUE); @@ -45,7 +51,7 @@ public class UidRangeTest extends TestCase { assertArrayEquals(inParcel, outParcel); } - @SmallTest + @Test public void testIndividualNativeFields() { UidRange original = new UidRange(0x11115678, 0x22224321); byte[] originalBytes = marshall(original); @@ -54,14 +60,14 @@ public class UidRangeTest extends TestCase { assertEquals(original.stop, getStop(originalBytes)); } - @SmallTest + @Test public void testSingleItemUidRangeAllowed() { new UidRange(123, 123); new UidRange(0, 0); new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE); } - @SmallTest + @Test public void testNegativeUidsDisallowed() { try { new UidRange(-2, 100); @@ -76,7 +82,7 @@ public class UidRangeTest extends TestCase { } } - @SmallTest + @Test public void testStopLessThanStartDisallowed() { final int x = 4195000; try { diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 5008a4188905..99a2ad942003 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -16,6 +16,16 @@ package android.net.apf; +import static android.system.OsConstants.*; +import static com.android.internal.util.BitUtils.bytesToBEInt; +import static com.android.internal.util.BitUtils.put; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; + import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; @@ -30,23 +40,22 @@ import android.net.metrics.RaEvent; import android.os.ConditionVariable; import android.os.Parcelable; import android.os.SystemClock; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.system.ErrnoException; import android.system.Os; -import android.test.AndroidTestCase; import android.text.format.DateUtils; -import android.test.suitebuilder.annotation.SmallTest; -import static android.system.OsConstants.*; import com.android.frameworks.tests.net.R; import com.android.internal.util.HexDump; -import static com.android.internal.util.BitUtils.bytesToBEInt; -import static com.android.internal.util.BitUtils.put; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; import java.io.File; import java.io.FileDescriptor; @@ -69,14 +78,15 @@ import libcore.io.Streams; * Build, install and run with: * runtest frameworks-net -c android.net.apf.ApfTest */ -public class ApfTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ApfTest { private static final int TIMEOUT_MS = 500; @Mock IpConnectivityLog mLog; - @Override + @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); // Load up native shared library containing APF interpreter exposed via JNI. System.loadLibrary("frameworksnettestsjni"); @@ -161,7 +171,7 @@ public class ApfTest extends AndroidTestCase { * generating bytecode for that program and running it through the * interpreter to verify it functions correctly. */ - @SmallTest + @Test public void testApfInstructions() throws IllegalInstructionException { // Empty program should pass because having the program counter reach the // location immediately after the program indicates the packet should be @@ -569,7 +579,7 @@ public class ApfTest extends AndroidTestCase { * Generate some BPF programs, translate them to APF, then run APF and BPF programs * over packet traces and verify both programs filter out the same packets. */ - @SmallTest + @Test public void testApfAgainstBpf() throws Exception { String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", @@ -739,7 +749,7 @@ public class ApfTest extends AndroidTestCase { private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; - @SmallTest + @Test public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); @@ -796,7 +806,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @SmallTest + @Test public void testApfFilterIPv6() throws Exception { final int[] ethTypeBlackList = {}; MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); @@ -830,7 +840,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @SmallTest + @Test public void testApfFilterMulticast() throws Exception { final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; @@ -922,7 +932,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @SmallTest + @Test public void testApfFilter802_3() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); @@ -973,7 +983,7 @@ public class ApfTest extends AndroidTestCase { apfFilter.shutdown(); } - @SmallTest + @Test public void testApfFilterEthTypeBL() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); @@ -1058,7 +1068,7 @@ public class ApfTest extends AndroidTestCase { assertDrop(program, garpReply()); } - @SmallTest + @Test public void testApfFilterArp() throws Exception { final int[] ethTypeBlackList = {}; MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); @@ -1136,7 +1146,7 @@ public class ApfTest extends AndroidTestCase { // Test that when ApfFilter is shown the given packet, it generates a program to filter it // for the given lifetime. - private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, + private void verifyRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, ByteBuffer packet, int lifetime) throws IOException, ErrnoException { // Verify new program generated if ApfFilter witnesses RA ipManagerCallback.resetApfProgramWait(); @@ -1181,7 +1191,7 @@ public class ApfTest extends AndroidTestCase { ipManagerCallback.assertNoProgramUpdate(); } - @SmallTest + @Test public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); final int[] ethTypeBlackList = {}; @@ -1212,7 +1222,7 @@ public class ApfTest extends AndroidTestCase { basePacket.put(IPV6_ALL_NODES_ADDRESS); assertPass(program, basePacket.array()); - testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME); + verifyRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1)); ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); @@ -1247,7 +1257,8 @@ public class ApfTest extends AndroidTestCase { prefixOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, PREFIX_VALID_LIFETIME); - testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); + verifyRaLifetime( + apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); verifyRaEvent(new RaEvent( ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1)); @@ -1259,7 +1270,7 @@ public class ApfTest extends AndroidTestCase { rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); rdnssOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME); - testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME); + verifyRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1)); ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( @@ -1270,7 +1281,7 @@ public class ApfTest extends AndroidTestCase { routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); routeInfoOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME); - testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME); + verifyRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1)); ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( @@ -1281,7 +1292,7 @@ public class ApfTest extends AndroidTestCase { dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); dnsslOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME); - testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME); + verifyRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME)); // Verify that current program filters all five RAs: @@ -1301,12 +1312,12 @@ public class ApfTest extends AndroidTestCase { * copy that resource into the app's data directory and return the path to it. */ private String stageFile(int rawId) throws Exception { - File file = new File(getContext().getFilesDir(), "staged_file"); + File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file"); new File(file.getParent()).mkdirs(); InputStream in = null; OutputStream out = null; try { - in = getContext().getResources().openRawResource(rawId); + in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId); out = new FileOutputStream(file); Streams.copy(in, out); } finally { @@ -1323,7 +1334,7 @@ public class ApfTest extends AndroidTestCase { buffer.position(original); } - @SmallTest + @Test public void testRaParsing() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); @@ -1343,7 +1354,7 @@ public class ApfTest extends AndroidTestCase { } } - @SmallTest + @Test public void testRaProcessing() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); @@ -1383,7 +1394,7 @@ public class ApfTest extends AndroidTestCase { private native static boolean compareBpfApf(String filter, String pcap_filename, byte[] apf_program); - @SmallTest + @Test public void testBroadcastAddress() throws Exception { assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0)); assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32)); diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java index d79c312a9edd..050183c1ac1f 100644 --- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java +++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java @@ -16,23 +16,36 @@ package android.net.dhcp; +import static android.net.dhcp.DhcpPacket.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import android.net.DhcpResults; import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.metrics.DhcpErrorEvent; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.system.OsConstants; -import android.test.suitebuilder.annotation.SmallTest; + import com.android.internal.util.HexDump; + import java.net.Inet4Address; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; -import junit.framework.TestCase; -import static android.net.dhcp.DhcpPacket.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; -public class DhcpPacketTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DhcpPacketTest { private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1"); private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234"); @@ -46,6 +59,7 @@ public class DhcpPacketTest extends TestCase { return (Inet4Address) NetworkUtils.numericToInetAddress(addrString); } + @Before public void setUp() { DhcpPacket.testOverrideVendorId = "android-dhcp-???"; DhcpPacket.testOverrideHostname = "android-01234567890abcde"; @@ -131,7 +145,7 @@ public class DhcpPacketTest extends TestCase { assertEquals(expectedVendorInfo, offerPacket.mVendorInfo); } - @SmallTest + @Test public void testDomainName() throws Exception { byte[] nullByte = new byte[] { 0x00 }; byte[] twoNullBytes = new byte[] { 0x00, 0x00 }; @@ -186,7 +200,7 @@ public class DhcpPacketTest extends TestCase { assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis()); } - @SmallTest + @Test public void testLeaseTime() throws Exception { byte[] noLease = null; byte[] tooShortLease = new byte[] { 0x00, 0x00 }; @@ -234,7 +248,7 @@ public class DhcpPacketTest extends TestCase { } } - @SmallTest + @Test public void testIpAddress() throws Exception { byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 }; byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 }; @@ -278,11 +292,11 @@ public class DhcpPacketTest extends TestCase { assertEquals(mtu, dhcpResults.mtu); } - @SmallTest + @Test public void testOffer1() throws Exception { - // TODO: Turn all of these into golden files. This will probably require modifying - // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read - // the golden files from the test APK's assets via mContext.getAssets(). + // TODO: Turn all of these into golden files. This will probably require using + // android.support.test.InstrumentationRegistry for obtaining a Context object + // to read such golden files, along with an appropriate Android.mk. final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // IP header. "451001480000000080118849c0a89003c0a89ff7" + @@ -311,7 +325,7 @@ public class DhcpPacketTest extends TestCase { null, "192.168.144.3", null, 7200, false, 0, dhcpResults); } - @SmallTest + @Test public void testOffer2() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // IP header. @@ -343,7 +357,7 @@ public class DhcpPacketTest extends TestCase { assertTrue(dhcpResults.hasMeteredHint()); } - @SmallTest + @Test public void testBadIpPacket() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -358,7 +372,7 @@ public class DhcpPacketTest extends TestCase { fail("Dhcp packet parsing should have failed"); } - @SmallTest + @Test public void testBadDhcpPacket() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -377,7 +391,7 @@ public class DhcpPacketTest extends TestCase { fail("Dhcp packet parsing should have failed"); } - @SmallTest + @Test public void testBadTruncatedOffer() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -406,7 +420,7 @@ public class DhcpPacketTest extends TestCase { fail("Dhcp packet parsing should have failed"); } - @SmallTest + @Test public void testBadOfferWithoutACookie() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -437,7 +451,7 @@ public class DhcpPacketTest extends TestCase { fail("Dhcp packet parsing should have failed"); } - @SmallTest + @Test public void testOfferWithBadCookie() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -473,7 +487,7 @@ public class DhcpPacketTest extends TestCase { assertEquals(Integer.toHexString(expected), Integer.toHexString(got)); } - @SmallTest + @Test public void testTruncatedOfferPackets() throws Exception { final byte[] packet = HexDump.hexStringToByteArray( // IP header. @@ -507,7 +521,7 @@ public class DhcpPacketTest extends TestCase { } } - @SmallTest + @Test public void testRandomPackets() throws Exception { final int maxRandomPacketSize = 512; final Random r = new Random(); @@ -547,7 +561,7 @@ public class DhcpPacketTest extends TestCase { null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults); } - @SmallTest + @Test public void testMtu() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // IP header. @@ -583,7 +597,7 @@ public class DhcpPacketTest extends TestCase { checkMtu(packet, 0, mtuBytes(-1)); } - @SmallTest + @Test public void testBadHwaddrLength() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // IP header. @@ -652,7 +666,7 @@ public class DhcpPacketTest extends TestCase { assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac())); } - @SmallTest + @Test public void testPadAndOverloadedOptionsOffer() throws Exception { // A packet observed in the real world that is interesting for two reasons: // @@ -691,7 +705,7 @@ public class DhcpPacketTest extends TestCase { null, "1.1.1.1", null, 43200, false, 0, dhcpResults); } - @SmallTest + @Test public void testBug2111() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // IP header. @@ -721,7 +735,7 @@ public class DhcpPacketTest extends TestCase { "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults); } - @SmallTest + @Test public void testBug2136() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // Ethernet header. @@ -754,7 +768,7 @@ public class DhcpPacketTest extends TestCase { "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults); } - @SmallTest + @Test public void testUdpServerAnySourcePort() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // Ethernet header. @@ -789,7 +803,7 @@ public class DhcpPacketTest extends TestCase { "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults); } - @SmallTest + @Test public void testUdpInvalidDstPort() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // Ethernet header. @@ -821,7 +835,7 @@ public class DhcpPacketTest extends TestCase { } catch (ParseException expected) {} } - @SmallTest + @Test public void testMultipleRouters() throws Exception { final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray( // Ethernet header. @@ -854,7 +868,7 @@ public class DhcpPacketTest extends TestCase { null, "192.171.189.2", null, 28800, false, 0, dhcpResults); } - @SmallTest + @Test public void testDiscoverPacket() throws Exception { short secs = 7; int transactionId = 0xdeadbeef; diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java index 5deba27d80dc..6647760f2ea9 100644 --- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java +++ b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java @@ -19,20 +19,30 @@ package android.net.netlink; import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK; import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.StructNlMsgErr; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.util.Log; + import java.nio.ByteBuffer; import java.nio.ByteOrder; -import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.Test; + import libcore.util.HexEncoding; -public class NetlinkErrorMessageTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetlinkErrorMessageTest { private final String TAG = "NetlinkErrorMessageTest"; // Hexadecimal representation of packet capture. @@ -54,7 +64,7 @@ public class NetlinkErrorMessageTest extends TestCase { public static final byte[] NLM_ERROR_OK = HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false); - @SmallTest + @Test public void testParseNlmErrorOk() { final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java index 78b3b704e786..bd36bac8d5e2 100644 --- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java +++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java @@ -16,25 +16,35 @@ package android.net.netlink; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.OsConstants; import android.util.Log; + import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.Test; -public class NetlinkSocketTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetlinkSocketTest { private final String TAG = "NetlinkSocketTest"; - @SmallTest + @Test public void testBasicWorkingGetNeighborsQuery() throws Exception { NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE); assertNotNull(s); @@ -93,7 +103,7 @@ public class NetlinkSocketTest extends TestCase { s.close(); } - @SmallTest + @Test public void testRepeatedCloseCallsAreQuiet() throws Exception { // Create a working NetlinkSocket. NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE); diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java index 029758eb6e5b..c9fd74fcddd9 100644 --- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java +++ b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java @@ -16,15 +16,19 @@ package android.net.netlink; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkMessage; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.system.OsConstants; import android.util.Log; -import libcore.util.HexEncoding; import java.net.Inet4Address; import java.net.InetAddress; @@ -32,10 +36,15 @@ import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; -import junit.framework.TestCase; +import org.junit.runner.RunWith; +import org.junit.Test; + +import libcore.util.HexEncoding; -public class RtNetlinkNeighborMessageTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RtNetlinkNeighborMessageTest { private final String TAG = "RtNetlinkNeighborMessageTest"; // Hexadecimal representation of packet capture. @@ -136,7 +145,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { public static final byte[] RTM_GETNEIGH_RESPONSE = HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false); - @SmallTest + @Test public void testParseRtmDelNeigh() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -163,7 +172,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination); } - @SmallTest + @Test public void testParseRtmNewNeigh() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -190,7 +199,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination); } - @SmallTest + @Test public void testParseRtmGetNeighResponse() { final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. @@ -215,7 +224,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase { assertEquals(14, messageCount); } - @SmallTest + @Test public void testCreateRtmNewNeighMessage() { final int seqNo = 2635; final int ifIndex = 14; diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/BlockingSocketReaderTest.java index 1aad4533d3d1..29dfa4c3d1e1 100644 --- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java +++ b/tests/net/java/android/net/util/BlockingSocketReaderTest.java @@ -18,15 +18,19 @@ package android.net.util; import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.os.Handler; import android.os.HandlerThread; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.system.ErrnoException; import android.system.Os; import android.system.StructTimeval; -import libcore.io.IoBridge; - import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; @@ -41,15 +45,21 @@ import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; +import org.junit.runner.RunWith; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import libcore.io.IoBridge; /** * Tests for BlockingSocketReader. * * @hide */ -public class BlockingSocketReaderTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BlockingSocketReaderTest { static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress(); static final StructTimeval TIMEO = StructTimeval.fromMillis(500); @@ -103,7 +113,7 @@ public class BlockingSocketReaderTest extends TestCase { } }; - @Override + @Before public void setUp() { resetLatch(); mLocalSocket = null; @@ -115,7 +125,7 @@ public class BlockingSocketReaderTest extends TestCase { mHandlerThread.start(); } - @Override + @After public void tearDown() throws Exception { if (mReceiver != null) { mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); }); @@ -143,6 +153,7 @@ public class BlockingSocketReaderTest extends TestCase { sender.close(); } + @Test public void testBasicWorking() throws Exception { final Handler h = mHandlerThread.getThreadHandler(); mReceiver = new UdpLoopbackReader(h); @@ -186,6 +197,7 @@ public class BlockingSocketReaderTest extends TestCase { public FileDescriptor createFd() { return null; } } + @Test public void testMinimalRecvBufSize() throws Exception { final Handler h = mHandlerThread.getThreadHandler(); diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java index dd679bc20090..38d3d74e64cf 100644 --- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java +++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java @@ -17,18 +17,25 @@ package android.net.util; import static android.net.util.NetworkConstants.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import libcore.util.HexEncoding; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; -import junit.framework.TestCase; +import org.junit.runner.RunWith; +import org.junit.Test; +import libcore.util.HexEncoding; /** * Tests for ConnectivityPacketSummary. * * @hide */ -public class ConnectivityPacketSummaryTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConnectivityPacketSummaryTest { private static final byte[] MYHWADDR = { asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3) }; @@ -39,6 +46,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { return ConnectivityPacketSummary.summarize(MYHWADDR, bytes); } + @Test public void testParseICMPv6DADProbe() { final String packet = // Ethernet @@ -60,6 +68,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseICMPv6RS() { final String packet = // Ethernet @@ -81,6 +90,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseICMPv6RA() { final String packet = // Ethernet @@ -113,6 +123,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseICMPv6NS() { final String packet = // Ethernet @@ -135,6 +146,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testInvalidICMPv6NDLength() { final String packet = // Ethernet @@ -159,6 +171,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseICMPv6NA() { final String packet = // Ethernet @@ -179,6 +192,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseARPRequest() { final String packet = // Ethernet @@ -197,6 +211,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseARPReply() { final String packet = // Ethernet @@ -217,6 +232,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertEquals(expected, getSummary(packet)); } + @Test public void testParseDHCPv4Discover() { final String packet = // Ethernet @@ -262,6 +278,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertTrue(getSummary(packet).startsWith(expectedPrefix)); } + @Test public void testParseDHCPv4Offer() { final String packet = // Ethernet @@ -307,6 +324,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertTrue(getSummary(packet).startsWith(expectedPrefix)); } + @Test public void testParseDHCPv4Request() { final String packet = // Ethernet @@ -354,6 +372,7 @@ public class ConnectivityPacketSummaryTest extends TestCase { assertTrue(getSummary(packet).startsWith(expectedPrefix)); } + @Test public void testParseDHCPv4Ack() { final String packet = // Ethernet diff --git a/tests/net/java/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java index c2d1608c461c..8903bf923fbf 100644 --- a/tests/net/java/android/net/util/IpUtilsTest.java +++ b/tests/net/java/android/net/util/IpUtilsTest.java @@ -16,15 +16,19 @@ package android.net.util; -import android.net.util.IpUtils; -import android.test.suitebuilder.annotation.SmallTest; +import static org.junit.Assert.assertEquals; -import java.nio.ByteBuffer; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; -import junit.framework.TestCase; +import java.nio.ByteBuffer; +import org.junit.runner.RunWith; +import org.junit.Test; -public class IpUtilsTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpUtilsTest { private static final int IPV4_HEADER_LENGTH = 20; private static final int IPV6_HEADER_LENGTH = 40; @@ -67,7 +71,7 @@ public class IpUtilsTest extends TestCase { // "hello") // print JavaPacketDefinition(str(packet)) - @SmallTest + @Test public void testIpv6TcpChecksum() throws Exception { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) / // scapy.TCP(sport=12345, dport=7, @@ -115,7 +119,7 @@ public class IpUtilsTest extends TestCase { assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); } - @SmallTest + @Test public void testIpv4UdpChecksum() { // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) / // scapy.UDP(sport=32012, dport=4500) / diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java index a423c2a55b3d..fb2bd79fed3a 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java @@ -24,12 +24,15 @@ import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import android.content.res.Resources; import android.net.NetworkStats; import android.net.TrafficStats; +import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; -import android.test.AndroidTestCase; +import android.support.test.runner.AndroidJUnit4; import com.android.frameworks.tests.net.R; @@ -42,19 +45,23 @@ import java.io.OutputStream; import libcore.io.IoUtils; import libcore.io.Streams; +import org.junit.runner.RunWith; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Tests for {@link NetworkStatsFactory}. */ +@RunWith(AndroidJUnit4.class) @SmallTest -public class NetworkStatsFactoryTest extends AndroidTestCase { +public class NetworkStatsFactoryTest { private File mTestProc; private NetworkStatsFactory mFactory; - @Override + @Before public void setUp() throws Exception { - super.setUp(); - - mTestProc = new File(getContext().getFilesDir(), "proc"); + mTestProc = new File(InstrumentationRegistry.getContext().getFilesDir(), "proc"); if (mTestProc.exists()) { IoUtils.deleteContents(mTestProc); } @@ -62,17 +69,16 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { mFactory = new NetworkStatsFactory(mTestProc); } - @Override + @After public void tearDown() throws Exception { mFactory = null; if (mTestProc.exists()) { IoUtils.deleteContents(mTestProc); } - - super.tearDown(); } + @Test public void testNetworkStatsDetail() throws Exception { final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical); @@ -84,6 +90,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L); } + @Test public void testKernelTags() throws Exception { assertEquals(0, kernelToTag("0x0000000000000000")); assertEquals(0x32, kernelToTag("0x0000003200000000")); @@ -98,6 +105,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertEquals(TrafficStats.TAG_SYSTEM_DOWNLOAD, kernelToTag("0xffffff0100000000")); } + @Test public void testNetworkStatsWithSet() throws Exception { final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical); assertEquals(70, stats.size()); @@ -106,6 +114,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L); } + @Test public void testNetworkStatsSingle() throws Exception { stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all")); @@ -116,6 +125,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L); } + @Test public void testNetworkStatsXt() throws Exception { stageFile(R.raw.xt_qtaguid_iface_fmt_typical, file("net/xt_qtaguid/iface_stat_fmt")); @@ -127,6 +137,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L); } + @Test public void testDoubleClatAccounting() throws Exception { NetworkStatsFactory.noteStackedIface("v4-wlan0", "wlan0"); @@ -161,6 +172,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { NetworkStatsFactory.noteStackedIface("v4-wlan0", null); } + @Test public void testDoubleClatAccounting100MBDownload() throws Exception { // Downloading 100mb from an ipv4 only destination in a foreground activity @@ -197,7 +209,7 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { InputStream in = null; OutputStream out = null; try { - in = getContext().getResources().openRawResource(rawId); + in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId); out = new FileOutputStream(file); Streams.copy(in, out); } finally { @@ -251,5 +263,4 @@ public class NetworkStatsFactoryTest extends AndroidTestCase { assertEquals("unexpected txBytes", txBytes, entry.txBytes); assertEquals("unexpected txPackets", txPackets, entry.txPackets); } - } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 335e62405c6c..d9586c2b31c5 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -26,8 +26,13 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.NetworkCapabilities.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import static com.android.internal.util.TestUtils.waitForIdleHandler; - import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; @@ -87,9 +92,10 @@ import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; -import android.test.AndroidTestCase; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentResolver; -import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -105,7 +111,11 @@ import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; +import org.junit.After; +import org.junit.Before; import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -123,13 +133,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; + /** * Tests for {@link ConnectivityService}. * * Build, install and run with: * runtest frameworks-net -c com.android.server.ConnectivityServiceTest */ -public class ConnectivityServiceTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConnectivityServiceTest { private static final String TAG = "ConnectivityServiceTest"; private static final int TIMEOUT_MS = 500; @@ -141,6 +154,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private MockNetworkAgent mWiFiNetworkAgent; private MockNetworkAgent mCellNetworkAgent; private MockNetworkAgent mEthernetNetworkAgent; + private Context mContext; // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods // do not go through ConnectivityService but talk to netd directly, so they don't automatically @@ -242,7 +256,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { waitForIdle(TIMEOUT_MS); } - @SmallTest + @Test public void testWaitForIdle() { final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng. @@ -743,7 +757,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks // can have odd side-effects, like network validations succeeding. - final Network[] networks = ConnectivityManager.from(getContext()).getAllNetworks(); + Context context = InstrumentationRegistry.getContext(); + final Network[] networks = ConnectivityManager.from(context).getAllNetworks(); boolean overlaps = false; for (Network network : networks) { if (netId == network.netId) { @@ -814,9 +829,9 @@ public class ConnectivityServiceTest extends AndroidTestCase { fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms"); } - @Override + @Before public void setUp() throws Exception { - super.setUp(); + mContext = InstrumentationRegistry.getContext(); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . @@ -824,7 +839,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { Looper.prepare(); } - mServiceContext = new MockContext(getContext()); + mServiceContext = new MockContext(InstrumentationRegistry.getContext()); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); @@ -835,7 +850,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { mock(IpConnectivityLog.class)); mService.systemReady(); - mCm = new WrappedConnectivityManager(getContext(), mService); + mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService); mCm.bindProcessToNetwork(null); // Ensure that the default setting for Captive Portals is used for most tests @@ -843,6 +858,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { setMobileDataAlwaysOn(false); } + @After public void tearDown() throws Exception { setMobileDataAlwaysOn(false); if (mCellNetworkAgent != null) { @@ -857,7 +873,6 @@ public class ConnectivityServiceTest extends AndroidTestCase { mEthernetNetworkAgent.disconnect(); mEthernetNetworkAgent = null; } - super.tearDown(); } private static int transportToLegacyType(int transport) { @@ -931,6 +946,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return cv; } + @Test public void testNetworkTypes() { // Ensure that our mocks for the networkAttributes config variable work as expected. If they // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types @@ -946,7 +962,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET)); } - @SmallTest + @Test public void testLingering() throws Exception { verifyNoNetwork(); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -987,7 +1003,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @SmallTest + @Test public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception { // Test bringing up unvalidated WiFi mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -1022,7 +1038,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @SmallTest + @Test public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception { // Test bringing up unvalidated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1048,7 +1064,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyNoNetwork(); } - @SmallTest + @Test public void testUnlingeringDoesNotValidate() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -1076,7 +1092,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { NET_CAPABILITY_VALIDATED)); } - @SmallTest + @Test public void testCellularOutscoresWeakWifi() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1102,7 +1118,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @SmallTest + @Test public void testReapingNetwork() throws Exception { // Test bringing up WiFi without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. @@ -1135,7 +1151,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { waitFor(cv); } - @SmallTest + @Test public void testCellularFallback() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1173,7 +1189,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @SmallTest + @Test public void testWiFiFallback() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -1387,7 +1403,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @SmallTest + @Test public void testStateChangeNetworkCallbacks() throws Exception { final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback(); final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); @@ -1477,7 +1493,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); } - @SmallTest + @Test public void testMultipleLingering() { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED) @@ -1705,7 +1721,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(trackDefaultCallback); } - @SmallTest + @Test public void testExplicitlySelected() { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) @@ -1872,7 +1888,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { handlerThread.quit(); } - @SmallTest + @Test public void testNetworkFactoryRequests() throws Exception { tryNetworkFactoryRequests(NET_CAPABILITY_MMS); tryNetworkFactoryRequests(NET_CAPABILITY_SUPL); @@ -1892,7 +1908,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed. } - @SmallTest + @Test public void testNoMutableNetworkRequests() throws Exception { PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0); NetworkRequest request1 = new NetworkRequest.Builder() @@ -1909,7 +1925,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertException(() -> { mCm.requestNetwork(request2, pendingIntent); }, expected); } - @SmallTest + @Test public void testMMSonWiFi() throws Exception { // Test bringing up cellular without MMS NetworkRequest gets reaped mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1948,7 +1964,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_WIFI); } - @SmallTest + @Test public void testMMSonCell() throws Exception { // Test bringing up cellular without MMS mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); @@ -1977,7 +1993,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { verifyActiveNetwork(TRANSPORT_CELLULAR); } - @SmallTest + @Test public void testCaptivePortal() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() @@ -2028,7 +2044,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); } - @SmallTest + @Test public void testCaptivePortalApp() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() @@ -2074,7 +2090,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(captivePortalCallback); } - @SmallTest + @Test public void testAvoidOrIgnoreCaptivePortals() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() @@ -2119,7 +2135,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI); } - @SmallTest + @Test public void testNetworkSpecifier() { NetworkRequest rEmpty1 = newWifiRequestBuilder().build(); NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build(); @@ -2180,7 +2196,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar); } - @SmallTest + @Test public void testInvalidNetworkSpecifier() { try { NetworkRequest.Builder builder = new NetworkRequest.Builder(); @@ -2241,7 +2257,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @SmallTest + @Test public void testNetworkSpecifierUidSpoofSecurityException() { class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable { @Override @@ -2275,7 +2291,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @SmallTest + @Test public void testRegisterDefaultNetworkCallback() throws Exception { final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultNetworkCallback); @@ -2324,7 +2340,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); } - @SmallTest + @Test public void testAdditionalStateCallbacks() throws Exception { // File a network request for mobile. final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); @@ -2385,7 +2401,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return nc.hasCapability(NET_CAPABILITY_FOREGROUND); } - @SmallTest + @Test public void testBackgroundNetworks() throws Exception { // Create a background request. We can't do this ourselves because ConnectivityService // doesn't have an API for it. So just turn on mobile data always on. @@ -2554,7 +2570,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return false; } - @SmallTest + @Test public void testMobileDataAlwaysOn() throws Exception { final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() @@ -2619,7 +2635,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { handlerThread.quit(); } - @SmallTest + @Test public void testAvoidBadWifiSetting() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); @@ -2657,7 +2673,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertTrue(tracker.shouldNotifyWifiUnvalidated()); } - @SmallTest + @Test public void testAvoidBadWifi() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); @@ -2784,7 +2800,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(defaultCallback); } - @SmallTest + @Test public void testMeteredMultipathPreferenceSetting() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); @@ -2808,7 +2824,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { * Validate that a satisfied network request does not trigger onUnavailable() once the * time-out period expires. */ - @SmallTest + @Test public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() { NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI).build(); @@ -2828,7 +2844,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { * Validate that a satisfied network request followed by a disconnected (lost) network does * not trigger onUnavailable() once the time-out period expires. */ - @SmallTest + @Test public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() { NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI).build(); @@ -2852,7 +2868,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { * callback is called when time-out expires. Then validate that if network request is * (somehow) satisfied - the callback isn't called later. */ - @SmallTest + @Test public void testTimedoutNetworkRequest() { NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI).build(); @@ -2873,7 +2889,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { * Validate that when a network request is unregistered (cancelled), no posterior event can * trigger the callback. */ - @SmallTest + @Test public void testNoCallbackAfterUnregisteredNetworkRequest() { NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI).build(); @@ -2981,7 +2997,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { return mWiFiNetworkAgent.getNetwork(); } - @SmallTest + @Test public void testPacketKeepalives() throws Exception { InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35"); @@ -3105,7 +3121,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { callback3.expectStopped(); } - @SmallTest + @Test public void testGetCaptivePortalServerUrl() throws Exception { String url = mCm.getCaptivePortalServerUrl(); assertEquals("http://connectivitycheck.gstatic.com/generate_204", url); @@ -3150,7 +3166,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); } - @SmallTest + @Test public void testNetworkPinner() { NetworkRequest wifiRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI) @@ -3210,7 +3226,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertPinnedToWifiWithCellDefault(); } - @SmallTest + @Test public void testNetworkCallbackMaximum() { final int MAX_REQUESTS = 100; final int CALLBACKS = 90; @@ -3302,7 +3318,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @SmallTest + @Test public void testNetworkInfoOfTypeNone() { ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1); @@ -3342,7 +3358,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } - @SmallTest + @Test public void testDeprecatedAndUnsupportedOperations() throws Exception { final int TYPE_NONE = ConnectivityManager.TYPE_NONE; assertNull(mCm.getNetworkInfo(TYPE_NONE)); @@ -3363,7 +3379,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertException(() -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); }, unsupported); } - @SmallTest + @Test public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() { final NetworkRequest networkRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI).build(); diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index efc58ccf7346..83ee361aa2e3 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -36,6 +36,7 @@ import android.net.IpSecUdpEncapResponse; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.system.ErrnoException; import android.system.Os; @@ -48,11 +49,10 @@ import java.net.UnknownHostException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; /** Unit tests for {@link IpSecService}. */ @SmallTest -@RunWith(JUnit4.class) +@RunWith(AndroidJUnit4.class) public class IpSecServiceTest { private static final int DROID_SPI = 0xD1201D; diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 77956be66c9e..354cf2f2239e 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -16,6 +16,18 @@ package com.android.server.connectivity; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.reset; + import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; @@ -24,27 +36,24 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMisc; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.text.format.DateUtils; + import com.android.internal.R; import com.android.server.ConnectivityService; import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; -import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.Before; +import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.reset; - -public class LingerMonitorTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LingerMonitorTest { static final String CELLULAR = "CELLULAR"; static final String WIFI = "WIFI"; @@ -62,6 +71,7 @@ public class LingerMonitorTest extends TestCase { @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; + @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mCtx.getResources()).thenReturn(mResources); @@ -71,7 +81,7 @@ public class LingerMonitorTest extends TestCase { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT); } - @SmallTest + @Test public void testTransitions() { setNotificationSwitch(transition(WIFI, CELLULAR)); NetworkAgentInfo nai1 = wifiNai(100); @@ -81,7 +91,7 @@ public class LingerMonitorTest extends TestCase { assertFalse(mMonitor.isNotificationEnabled(nai2, nai1)); } - @SmallTest + @Test public void testNotificationOnLinger() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -92,7 +102,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(from, to); } - @SmallTest + @Test public void testToastOnLinger() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); @@ -103,7 +113,7 @@ public class LingerMonitorTest extends TestCase { verifyToast(from, to); } - @SmallTest + @Test public void testNotificationClearedAfterDisconnect() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -117,7 +127,7 @@ public class LingerMonitorTest extends TestCase { verify(mNotifier, times(1)).clearNotification(100); } - @SmallTest + @Test public void testNotificationClearedAfterSwitchingBack() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -131,7 +141,7 @@ public class LingerMonitorTest extends TestCase { verify(mNotifier, times(1)).clearNotification(100); } - @SmallTest + @Test public void testUniqueToast() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); @@ -149,7 +159,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testMultipleNotifications() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -168,7 +178,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(wifi2, cell); } - @SmallTest + @Test public void testRateLimiting() throws InterruptedException { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT); @@ -194,7 +204,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testDailyLimiting() throws InterruptedException { mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT); @@ -221,7 +231,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testUniqueNotification() { setNotificationSwitch(transition(WIFI, CELLULAR)); setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); @@ -238,7 +248,7 @@ public class LingerMonitorTest extends TestCase { verifyNotification(from, to); } - @SmallTest + @Test public void testIgnoreNeverValidatedNetworks() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -250,7 +260,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testIgnoreCurrentlyValidatedNetworks() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -262,7 +272,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testNoNotificationType() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(); @@ -273,7 +283,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testNoTransitionToNotify() { setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE); setNotificationSwitch(transition(WIFI, CELLULAR)); @@ -284,7 +294,7 @@ public class LingerMonitorTest extends TestCase { verifyNoNotifications(); } - @SmallTest + @Test public void testDifferentTransitionToNotify() { setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); setNotificationSwitch(transition(CELLULAR, WIFI)); diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java index 911347c13478..125fe7258e94 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java @@ -34,20 +34,29 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.telephony.TelephonyManager; -import android.test.suitebuilder.annotation.SmallTest; + import com.android.server.connectivity.NetworkNotificationManager.NotificationType; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.Before; +import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -public class NetworkNotificationManagerTest extends TestCase { + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetworkNotificationManagerTest { static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities(); static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities(); @@ -71,6 +80,7 @@ public class NetworkNotificationManagerTest extends TestCase { NetworkNotificationManager mManager; + @Before public void setUp() { MockitoAnnotations.initMocks(this); mCaptor = ArgumentCaptor.forClass(Notification.class); @@ -87,7 +97,7 @@ public class NetworkNotificationManagerTest extends TestCase { mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager); } - @SmallTest + @Test public void testNotificationsShownAndCleared() { final int NETWORK_ID_BASE = 100; List<NotificationType> types = Arrays.asList(NotificationType.values()); @@ -117,7 +127,7 @@ public class NetworkNotificationManagerTest extends TestCase { } } - @SmallTest + @Test public void testNoInternetNotificationsNotShownForCellular() { mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false); mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false); @@ -131,7 +141,7 @@ public class NetworkNotificationManagerTest extends TestCase { verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any()); } - @SmallTest + @Test public void testNotificationsNotShownIfNoInternetCapability() { mWifiNai.networkCapabilities = new NetworkCapabilities(); mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); @@ -142,7 +152,7 @@ public class NetworkNotificationManagerTest extends TestCase { verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); } - @SmallTest + @Test public void testDuplicatedNotificationsNoInternetThenSignIn() { final int id = 101; final String tag = NetworkNotificationManager.tagFor(id); @@ -164,7 +174,7 @@ public class NetworkNotificationManagerTest extends TestCase { verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any()); } - @SmallTest + @Test public void testDuplicatedNotificationsSignInThenNoInternet() { final int id = 101; final String tag = NetworkNotificationManager.tagFor(id); diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 4f18da7056ef..fe396c3a5c40 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -20,6 +20,9 @@ import static android.content.pm.UserInfo.FLAG_ADMIN; import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_RESTRICTED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.AdditionalMatchers.*; import static org.mockito.Mockito.*; @@ -42,14 +45,17 @@ import android.os.INetworkManagementService; import android.os.Looper; import android.os.UserHandle; import android.os.UserManager; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.filters.SmallTest; import android.util.ArrayMap; import android.util.ArraySet; import com.android.internal.R; import com.android.internal.net.VpnConfig; +import org.junit.runner.RunWith; +import org.junit.Before; +import org.junit.Test; import org.mockito.Answers; import org.mockito.InOrder; import org.mockito.Mock; @@ -61,13 +67,16 @@ import java.util.Collections; import java.util.Map; import java.util.Set; + /** * Tests for {@link Vpn}. * * Build, install and run with: - * runtest --path java/com/android/server/connectivity/VpnTest.java + * runtest frameworks-net -c com.android.server.connectivity.VpnTest */ -public class VpnTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VpnTest { private static final String TAG = "VpnTest"; // Mock users @@ -106,7 +115,7 @@ public class VpnTest extends AndroidTestCase { @Mock private NotificationManager mNotificationManager; @Mock private Vpn.SystemServices mSystemServices; - @Override + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -130,7 +139,7 @@ public class VpnTest extends AndroidTestCase { doNothing().when(mNetService).registerObserver(any()); } - @SmallTest + @Test public void testRestrictedProfilesAreAddedToVpn() { setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); @@ -144,7 +153,7 @@ public class VpnTest extends AndroidTestCase { })), ranges); } - @SmallTest + @Test public void testManagedProfilesAreNotAddedToVpn() { setMockedUsers(primaryUser, managedProfileA); @@ -157,7 +166,7 @@ public class VpnTest extends AndroidTestCase { })), ranges); } - @SmallTest + @Test public void testAddUserToVpnOnlyAddsOneUser() { setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); @@ -170,7 +179,7 @@ public class VpnTest extends AndroidTestCase { })), ranges); } - @SmallTest + @Test public void testUidWhiteAndBlacklist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); @@ -195,7 +204,7 @@ public class VpnTest extends AndroidTestCase { })), disallow); } - @SmallTest + @Test public void testLockdownChangingPackage() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); @@ -230,7 +239,7 @@ public class VpnTest extends AndroidTestCase { assertUnblocked(vpn, user.start + PKG_UIDS[3]); } - @SmallTest + @Test public void testLockdownAddingAProfile() throws Exception { final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); @@ -270,7 +279,7 @@ public class VpnTest extends AndroidTestCase { })); } - @SmallTest + @Test public void testLockdownRuleRepeatability() throws Exception { final Vpn vpn = createVpn(primaryUser.id); @@ -293,7 +302,7 @@ public class VpnTest extends AndroidTestCase { verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class)); } - @SmallTest + @Test public void testLockdownRuleReversibility() throws Exception { final Vpn vpn = createVpn(primaryUser.id); @@ -322,7 +331,7 @@ public class VpnTest extends AndroidTestCase { order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); } - @SmallTest + @Test public void testIsAlwaysOnPackageSupported() throws Exception { final Vpn vpn = createVpn(primaryUser.id); @@ -356,7 +365,7 @@ public class VpnTest extends AndroidTestCase { assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0])); } - @SmallTest + @Test public void testNotificationShownForAlwaysOnApp() { final UserHandle userHandle = UserHandle.of(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); |