diff options
140 files changed, 3615 insertions, 1767 deletions
diff --git a/api/current.txt b/api/current.txt index da601e1519a8..72c049bf52dd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6994,12 +6994,12 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -10217,12 +10217,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -10341,7 +10341,7 @@ package android.content.pm { public class LauncherApps { method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -24011,7 +24011,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -24047,12 +24046,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -24261,8 +24254,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -24281,8 +24272,6 @@ package android.media.session { method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -24360,14 +24349,11 @@ package android.media.session { method public void setSessionActivity(android.app.PendingIntent); method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -24381,8 +24367,6 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); @@ -30802,6 +30786,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -30826,6 +30811,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -31355,6 +31341,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -31400,6 +31387,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -32030,15 +32018,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -32050,7 +32039,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -35487,6 +35479,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -37150,6 +37152,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -37341,7 +37344,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -37421,16 +37423,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37443,7 +37445,7 @@ package android.service.notification { method public final void requestUnbind(); method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -49733,6 +49735,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); diff --git a/api/removed.txt b/api/removed.txt index 1e8370e97dc5..0f5b81abad4c 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -22,6 +22,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -37,6 +51,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -180,10 +198,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/api/system-current.txt b/api/system-current.txt index 21fce319ebe9..47d460dcc812 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1197,6 +1197,8 @@ package android { field public static final int requiredFeature = 16844119; // 0x1010557 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 field public static final int requiredNotFeature = 16844120; // 0x1010558 + field public static final int requiredSystemPropertyName = 16844136; // 0x1010568 + field public static final int requiredSystemPropertyValue = 16844137; // 0x1010569 field public static final int requiresFadingEdge = 16843685; // 0x10103a5 field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364 field public static final int resizeClip = 16843983; // 0x10104cf @@ -7457,12 +7459,12 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -10790,12 +10792,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -11004,7 +11006,7 @@ package android.content.pm { public class LauncherApps { method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -25931,7 +25933,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -25967,12 +25968,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -26181,8 +26176,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -26201,8 +26194,6 @@ package android.media.session { method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -26280,14 +26271,11 @@ package android.media.session { method public void setSessionActivity(android.app.PendingIntent); method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -26301,8 +26289,6 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); @@ -33559,6 +33545,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -33583,6 +33570,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -34142,6 +34130,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -34187,6 +34176,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -34922,15 +34912,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -34942,7 +34933,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -38136,7 +38130,6 @@ package android.provider { field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field public static final java.lang.String MODE_RINGER = "mode_ringer"; field public static final java.lang.String NETWORK_PREFERENCE = "network_preference"; - field public static final java.lang.String NETWORK_RECOMMENDATIONS_ENABLED = "network_recommendations_enabled"; field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth"; field public static final java.lang.String RADIO_CELL = "cell"; @@ -38586,6 +38579,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -40261,6 +40264,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -40452,7 +40456,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -40560,16 +40563,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -40586,7 +40589,7 @@ package android.service.notification { method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); method public void unregisterAsSystemService() throws android.os.RemoteException; - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -53675,6 +53678,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); diff --git a/api/system-removed.txt b/api/system-removed.txt index 7bdb9571bad0..823d88faaece 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -20,6 +20,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -35,6 +49,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -174,10 +192,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/api/test-current.txt b/api/test-current.txt index bd2fed09c9d6..b8ed13db87fb 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -7024,13 +7024,13 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public boolean isQuotaSupported(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public boolean isQuotaSupported(java.util.UUID); + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -10253,12 +10253,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -10378,7 +10378,7 @@ package android.content.pm { public class LauncherApps { ctor public LauncherApps(android.content.Context); method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -24118,7 +24118,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -24154,12 +24153,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -24368,8 +24361,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -24388,8 +24379,6 @@ package android.media.session { method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -24467,14 +24456,11 @@ package android.media.session { method public void setSessionActivity(android.app.PendingIntent); method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -24488,8 +24474,6 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); @@ -30909,6 +30893,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -30933,6 +30918,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -31483,6 +31469,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -31528,6 +31515,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -32162,15 +32150,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -32182,7 +32171,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -35627,6 +35619,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -37303,6 +37305,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -37494,7 +37497,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -37600,16 +37602,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37623,7 +37625,7 @@ package android.service.notification { method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -50112,6 +50114,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); diff --git a/api/test-removed.txt b/api/test-removed.txt index 1e8370e97dc5..0f5b81abad4c 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -22,6 +22,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -37,6 +51,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -180,10 +198,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp index 67874a8b9c02..d69dd79555a1 100644 --- a/cmds/idmap/scan.cpp +++ b/cmds/idmap/scan.cpp @@ -10,6 +10,7 @@ #include <androidfw/StreamingZipInflater.h> #include <androidfw/ZipFileRO.h> #include <cutils/jstring.h> +#include <cutils/properties.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM #include <utils/SortedVector.h> #include <utils/String16.h> @@ -82,12 +83,26 @@ namespace { return String8(tmp); } + bool check_property(String16 property, String16 value) { + const char *prop; + const char *val; + + prop = strndup16to8(property.string(), property.size()); + char propBuf[PROPERTY_VALUE_MAX]; + property_get(prop, propBuf, NULL); + val = strndup16to8(value.string(), value.size()); + + return (strcmp(propBuf, val) == 0); + } + int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name, bool* is_static_overlay) { const size_t N = parser.getAttributeCount(); String16 target; int priority = -1; + String16 propName = String16(); + String16 propValue = String16(); for (size_t i = 0; i < N; ++i) { size_t len; String16 key(parser.getAttributeName(i, &len)); @@ -109,34 +124,32 @@ namespace { if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) { *is_static_overlay = (v.data != 0); } - } - } - if (target == String16(target_package_name)) { - return priority; - } - return NO_OVERLAY_TAG; - } - - String16 parse_package_name(const ResXMLTree& parser) - { - const size_t N = parser.getAttributeCount(); - String16 package_name; - for (size_t i = 0; i < N; ++i) { - size_t len; - String16 key(parser.getAttributeName(i, &len)); - if (key == String16("package")) { + } else if (key == String16("requiredSystemPropertyName")) { const char16_t *p = parser.getAttributeStringValue(i, &len); if (p != NULL) { - package_name = String16(p, len); + propName = String16(p, len); + } + } else if (key == String16("requiredSystemPropertyValue")) { + const char16_t *p = parser.getAttributeStringValue(i, &len); + if (p != NULL) { + propValue = String16(p, len); } } } - return package_name; - } - bool isValidStaticOverlayPackage(const String16& package_name) { - // TODO(b/35742444): Need to support selection method based on a package name. - return package_name.size() > 0; + // Note that conditional property enablement/exclusion only applies if + // the attribute is present. In its absence, all overlays are presumed enabled. + if (propName.size() > 0 && propValue.size() > 0) { + // if property set & equal to value, then include overlay - otherwise skip + if (!check_property(propName, propValue)) { + return NO_OVERLAY_TAG; + } + } + + if (target == String16(target_package_name)) { + return priority; + } + return NO_OVERLAY_TAG; } int parse_manifest(const void *data, size_t size, const char *target_package_name) @@ -149,7 +162,6 @@ namespace { } ResXMLParser::event_code_t type; - String16 package_name; bool is_static_overlay = false; int priority = NO_OVERLAY_TAG; do { @@ -157,16 +169,14 @@ namespace { if (type == ResXMLParser::START_TAG) { size_t len; String16 tag(parser.getElementName(&len)); - if (tag == String16("manifest")) { - package_name = parse_package_name(parser); - } else if (tag == String16("overlay")) { + if (tag == String16("overlay")) { priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay); break; } } } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT); - if (is_static_overlay && isValidStaticOverlayPackage(package_name)) { + if (is_static_overlay) { return priority; } return NO_OVERLAY_TAG; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index b36a1600bae5..169dcb01c90a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,21 +16,16 @@ package android.app; -import android.metrics.LogMaker; import android.graphics.Rect; import android.os.SystemClock; import android.view.ViewRootImpl.ActivityConfigCallback; -import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillPopupWindow; -import android.view.autofill.AutofillValue; import android.view.autofill.IAutofillWindowPresenter; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; import com.android.internal.policy.PhoneWindow; import android.annotation.CallSuper; @@ -1234,6 +1229,13 @@ public class Activity extends ContextThemeWrapper mFragments.doLoaderStart(); getApplication().dispatchActivityStarted(this); + + if (mAutoFillResetNeeded) { + AutofillManager afm = getAutofillManager(); + if (afm != null) { + afm.onVisibleForAutofill(); + } + } } /** @@ -7407,6 +7409,54 @@ public class Activity extends ContextThemeWrapper return true; } + /** @hide */ + @Override + public boolean getViewVisibility(int viewId) { + Window window = getWindow(); + if (window == null) { + Log.i(TAG, "no window"); + return false; + } + + View decorView = window.peekDecorView(); + if (decorView == null) { + Log.i(TAG, "no decorView"); + return false; + } + + View view = decorView.findViewByAccessibilityIdTraversal(viewId); + if (view == null) { + Log.i(TAG, "cannot find view"); + return false; + } + + // Check if the view is visible by checking all parents + while (view != null) { + if (view == decorView) { + break; + } + + if (view.getVisibility() != View.VISIBLE) { + Log.i(TAG, view + " is not visible"); + return false; + } + + if (view.getParent() instanceof View) { + view = (View) view.getParent(); + } else { + break; + } + } + + return true; + } + + /** @hide */ + @Override + public boolean isVisibleForAutofill() { + return !mStopped; + } + /** * If set to true, this indicates to the system that it should never take a * screenshot of the activity to be used as a representation while it is not in a started state. diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index f4e8f3f5687e..cd9c095890e7 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.pm.ParceledListSlice; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.service.notification.Adjustment; import android.service.notification.Condition; import android.service.notification.IConditionListener; @@ -101,9 +102,9 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); - void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in NotificationChannel channel); - ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg); - ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg); + void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user, in NotificationChannel channel); + ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); + ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); void applyEnqueuedAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java index 6fc4f5c1c95c..4b6479ad4a7b 100644 --- a/core/java/android/app/usage/StorageStatsManager.java +++ b/core/java/android/app/usage/StorageStatsManager.java @@ -16,17 +16,25 @@ package android.app.usage; +import static android.os.storage.StorageManager.convert; + +import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.WorkerThread; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.ParcelableException; import android.os.RemoteException; import android.os.UserHandle; +import android.os.storage.StorageManager; import com.android.internal.util.Preconditions; import java.io.File; +import java.io.IOException; +import java.util.UUID; /** * Provides access to detailed storage statistics. @@ -50,36 +58,49 @@ public class StorageStatsManager { /** {@hide} */ @TestApi - public boolean isQuotaSupported(String volumeUuid) { + public boolean isQuotaSupported(@NonNull UUID storageUuid) { try { - return mService.isQuotaSupported(volumeUuid, mContext.getOpPackageName()); + return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public boolean isQuotaSupported(String uuid) { + return isQuotaSupported(convert(uuid)); + } + /** - * Return the total space on the requested storage volume. + * Return the total size of the media hosting this storage volume. * <p> - * To reduce end user confusion, this value is the total storage size + * To reduce end user confusion, this value matches the total storage size * advertised in a retail environment, which is typically larger than the - * actual writable partition total size. - * <p> - * This method may take several seconds to calculate the requested values, - * so it should only be called from a worker thread. + * actual usable partition space. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. */ @WorkerThread - public long getTotalBytes(String volumeUuid) { + public long getTotalBytes(@NonNull UUID storageUuid) throws IOException { try { - return mService.getTotalBytes(volumeUuid, mContext.getOpPackageName()); + return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getTotalBytes(String uuid) throws IOException { + return getTotalBytes(convert(uuid)); + } + /** * Return the free space on the requested storage volume. * <p> @@ -90,18 +111,28 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. */ @WorkerThread - public long getFreeBytes(String volumeUuid) { + public long getFreeBytes(@NonNull UUID storageUuid) throws IOException { try { - return mService.getFreeBytes(volumeUuid, mContext.getOpPackageName()); + return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getFreeBytes(String uuid) throws IOException { + return getFreeBytes(convert(uuid)); + } + /** * Return storage statistics for a specific package on the requested storage * volume. @@ -112,27 +143,41 @@ public class StorageStatsManager { * Note: if the requested package uses the {@code android:sharedUserId} * manifest feature, this call will be forced into a slower manual * calculation path. If possible, consider always using - * {@link #queryStatsForUid(String, int)}, which is typically faster. + * {@link #queryStatsForUid(UUID, int)}, which is typically faster. * </p> * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param packageName the package name you're interested in. * @param user the user you're interested in. - * @see ApplicationInfo#volumeUuid + * @throws PackageManager.NameNotFoundException when the requested package + * name isn't installed for the requested user. + * @throws IOException when the storage device isn't present. + * @see ApplicationInfo#storageUuid * @see PackageInfo#packageName */ @WorkerThread - public StorageStats queryStatsForPackage(String volumeUuid, String packageName, - UserHandle user) { + public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid, String packageName, + UserHandle user) throws PackageManager.NameNotFoundException, IOException { try { - return mService.queryStatsForPackage(volumeUuid, packageName, user.getIdentifier(), - mContext.getOpPackageName()); + return mService.queryStatsForPackage(convert(storageUuid), packageName, + user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(PackageManager.NameNotFoundException.class); + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForPackage(String uuid, String packageName, + UserHandle user) throws PackageManager.NameNotFoundException, IOException { + return queryStatsForPackage(convert(uuid), packageName, user); + } + /** * Return storage statistics for a specific UID on the requested storage * volume. @@ -140,21 +185,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param uid the UID you're interested in. - * @see ApplicationInfo#volumeUuid + * @throws IOException when the storage device isn't present. + * @see ApplicationInfo#storageUuid * @see ApplicationInfo#uid */ @WorkerThread - public StorageStats queryStatsForUid(String volumeUuid, int uid) { + public StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid) throws IOException { try { - return mService.queryStatsForUid(volumeUuid, uid, mContext.getOpPackageName()); + return mService.queryStatsForUid(convert(storageUuid), uid, + mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForUid(String uuid, int uid) throws IOException { + return queryStatsForUid(convert(uuid), uid); + } + /** * Return storage statistics for a specific {@link UserHandle} on the * requested storage volume. @@ -162,21 +218,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param user the user you're interested in. + * @throws IOException when the storage device isn't present. * @see android.os.Process#myUserHandle() */ @WorkerThread - public StorageStats queryStatsForUser(String volumeUuid, UserHandle user) { + public StorageStats queryStatsForUser(@NonNull UUID storageUuid, UserHandle user) + throws IOException { try { - return mService.queryStatsForUser(volumeUuid, user.getIdentifier(), + return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException { + return queryStatsForUser(convert(uuid), user); + } + /** * Return shared/external storage statistics for a specific * {@link UserHandle} on the requested storage volume. @@ -184,20 +251,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. * @see android.os.Process#myUserHandle() */ @WorkerThread - public ExternalStorageStats queryExternalStatsForUser(String volumeUuid, UserHandle user) { + public ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid, + UserHandle user) throws IOException { try { - return mService.queryExternalStatsForUser(volumeUuid, user.getIdentifier(), + return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user) + throws IOException { + return queryExternalStatsForUser(convert(uuid), user); + } + /** {@hide} */ public long getCacheQuotaBytes(String volumeUuid, int uid) { try { diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index ef3b1c50ffd3..624ec871a15a 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -498,8 +498,13 @@ public class AppWidgetHostView extends FrameLayout { private void updateContentDescription(AppWidgetProviderInfo info) { if (info != null) { LauncherApps launcherApps = getContext().getSystemService(LauncherApps.class); - ApplicationInfo appInfo = launcherApps.getApplicationInfo( - info.provider.getPackageName(), 0, info.getProfile()); + ApplicationInfo appInfo = null; + try { + appInfo = launcherApps.getApplicationInfo( + info.provider.getPackageName(), 0, info.getProfile()); + } catch (NameNotFoundException e) { + // ignore -- use null. + } if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0) { setContentDescription( diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 5f53e27eeb07..8b2809af5cb2 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -29,6 +29,7 @@ import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.Printer; import android.util.SparseArray; @@ -41,6 +42,7 @@ import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; +import java.util.UUID; /** * Information you can retrieve about a particular application. This @@ -621,12 +623,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public float maxAspectRatio; + /** @removed */ + @Deprecated + public String volumeUuid; + /** * UUID of the storage volume on which this application is being hosted. For * apps hosted on the default internal storage at - * {@link Environment#getDataDirectory()}, the UUID value is {@code null}. + * {@link Environment#getDataDirectory()}, the UUID value is + * {@link StorageManager#UUID_DEFAULT}. */ - public String volumeUuid; + public UUID storageUuid; /** {@hide} */ public String scanSourceDir; @@ -1134,6 +1141,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { compatibleWidthLimitDp = orig.compatibleWidthLimitDp; largestWidthLimitDp = orig.largestWidthLimitDp; volumeUuid = orig.volumeUuid; + storageUuid = orig.storageUuid; scanSourceDir = orig.scanSourceDir; scanPublicSourceDir = orig.scanPublicSourceDir; sourceDir = orig.sourceDir; @@ -1195,7 +1203,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(requiresSmallestWidthDp); dest.writeInt(compatibleWidthLimitDp); dest.writeInt(largestWidthLimitDp); - dest.writeString(volumeUuid); + dest.writeUuid(storageUuid); dest.writeString(scanSourceDir); dest.writeString(scanPublicSourceDir); dest.writeString(sourceDir); @@ -1257,7 +1265,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { requiresSmallestWidthDp = source.readInt(); compatibleWidthLimitDp = source.readInt(); largestWidthLimitDp = source.readInt(); - volumeUuid = source.readString(); + storageUuid = source.readUuid(); + volumeUuid = StorageManager.convert(storageUuid); scanSourceDir = source.readString(); scanPublicSourceDir = source.readString(); sourceDir = source.readString(); diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c3bdde51af0f..8ead0ec612f8 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -22,6 +22,8 @@ import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -52,6 +54,8 @@ import android.os.UserManager; import android.util.DisplayMetrics; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -612,11 +616,20 @@ public class LauncherApps { * null if the package isn't installed for the given user, or the target user * is not enabled. */ - public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, - UserHandle user) { + public ApplicationInfo getApplicationInfo(@NonNull String packageName, + @ApplicationInfoFlags int flags, @NonNull UserHandle user) + throws PackageManager.NameNotFoundException { + Preconditions.checkNotNull(packageName, "packageName"); + Preconditions.checkNotNull(packageName, "user"); logErrorForInvalidProfileAccess(user); try { - return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); + final ApplicationInfo ai = mService + .getApplicationInfo(mContext.getPackageName(), packageName, flags, user); + if (ai == null) { + throw new NameNotFoundException("Package " + packageName + " not found for user " + + user.getIdentifier()); + } + return ai; } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -1268,15 +1281,34 @@ public class LauncherApps { * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent * respectively to the default launcher app. * - * <p>Note the launcher may receive a request to pin a shortcut that is already pinned, because - * the user may actually want to have multiple icons of the same shortcut on the launcher. - * The launcher can tell this case by calling {@link ShortcutInfo#isPinned()} on the shortcut - * returned by {@link #getShortcutInfo()}. In this case, calling {@link #accept()} is optional; - * even if the launcher does not call it, the shortcut is already pinned. Also in this case, - * the {@code options} argument to {@link #accept(Bundle)} will be ignored. + * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type. + * + * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a + * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()}, + * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for + * pin-shortcuts requests. + * + * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type. + * + * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in + * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create + * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it, + * {@link #accept()} must still be called even though the shortcut is already pinned, and + * create a new pinned shortcut icon for it. + * + * <p>See also {@link ShortcutManager} for more details. + * + * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type. + * + * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a + * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with + * the appwidget integer ID set to the + * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra. + * + * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null + * {@link AppWidgetProviderInfo} for this type. * - * <p>For AppWidget pin requests launcher should send back the appwidget id as an extra for - * {@link #accept(Bundle)} as {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}. + * <p>See also {@link AppWidgetManager} for more details. * * @see #EXTRA_PIN_ITEM_REQUEST * @see #getPinItemRequest(Intent) @@ -1306,8 +1338,9 @@ public class LauncherApps { } /** - * Represents the type of a request. For now {@link #REQUEST_TYPE_SHORTCUT} is the only - * valid type. + * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants. + * + * @return one of the {@code REQUEST_TYPE_} constants. */ @RequestType public int getRequestType() { @@ -1315,8 +1348,12 @@ public class LauncherApps { } /** - * {@link ShortcutInfo} sent by the requesting app. Always non-null for a - * {@link #REQUEST_TYPE_SHORTCUT} request. + * {@link ShortcutInfo} sent by the requesting app. + * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a + * different request type. + * + * @return requested {@link ShortcutInfo} when a request is of the + * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise. */ @Nullable public ShortcutInfo getShortcutInfo() { @@ -1328,8 +1365,12 @@ public class LauncherApps { } /** - * {@link AppWidgetProviderInfo} sent by the requesting app. Always non-null for a - * {@link #REQUEST_TYPE_APPWIDGET} request. + * {@link AppWidgetProviderInfo} sent by the requesting app. + * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a + * different request type. + * + * @return requested {@link AppWidgetProviderInfo} when a request is of the + * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise. */ @Nullable public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) { @@ -1347,6 +1388,11 @@ public class LauncherApps { /** * Any extras sent by the requesting app. + * + * @return For a shortcut request, this method always return null. For an AppWidget + * request, this method returns the extras passed to the + * {@link android.appwidget.AppWidgetManager#requestPinAppWidget( + * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details. */ @Nullable public Bundle getExtras() { @@ -1358,8 +1404,9 @@ public class LauncherApps { } /** - * Return {@code TRUE} if a request is valid -- i.e. {@link #accept(Bundle)} has not been - * called yet. + * Return whether a request is still valid. + * + * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called. */ public boolean isValid() { try { @@ -1371,6 +1418,12 @@ public class LauncherApps { /** * Called by the receiving launcher app when the user accepts the request. + * + * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request. + * + * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned. + * {@code FALSE} if the item hasn't been pinned, for example, because the request had + * already been canceled, in which case the launcher must not pin the requested item. */ public boolean accept(@Nullable Bundle options) { try { @@ -1381,7 +1434,11 @@ public class LauncherApps { } /** - * Same as as {@link #accept(Bundle)} with no options. + * Called by the receiving launcher app when the user accepts the request, with no options. + * + * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned. + * {@code FALSE} if the item hasn't been pinned, for example, because the request had + * already been canceled, in which case the launcher must not pin the requested item. */ public boolean accept() { return accept(/* options= */ null); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 430d8b15216f..1f78bff9e1a7 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -64,8 +64,10 @@ import android.os.FileUtils; import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.OsConstants; import android.system.StructStat; @@ -116,6 +118,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; @@ -2111,6 +2114,12 @@ public class PackageParser { pkg.mIsStaticOverlay = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic, false); + final String propName = sa.getString( + com.android.internal.R.styleable + .AndroidManifestResourceOverlay_requiredSystemPropertyName); + final String propValue = sa.getString( + com.android.internal.R.styleable + .AndroidManifestResourceOverlay_requiredSystemPropertyValue); sa.recycle(); if (pkg.mOverlayTarget == null) { @@ -2118,15 +2127,22 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } + if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { outError[0] = "<overlay> priority must be between 0 and 9999"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } - if (pkg.mIsStaticOverlay) { - // TODO(b/35742444): Need to support selection method based on a package name. + + // check to see if overlay should be excluded based on system property condition + if (!checkOverlayRequiredSystemProperty(propName, propValue)) { + Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and " + + pkg.baseCodePath+ ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + return null; } + XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_KEY_SETS)) { @@ -2531,6 +2547,25 @@ public class PackageParser { return pkg; } + private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { + + if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { + if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { + // malformed condition - incomplete + Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName + + "=" + propValue + "' - require both requiredSystemPropertyName" + + " AND requiredSystemPropertyValue to be specified."); + return false; + } + // no valid condition set - so no exclusion criteria, overlay will be included. + return true; + } + + // check property value - make sure it is both set and equal to expected value + final String currValue = SystemProperties.get(propName); + return (currValue != null && currValue.equals(propValue)); + } + /** * This is a pre-density application which will get scaled - instead of being pixel perfect. * This type of application is not resizable. @@ -5741,11 +5776,14 @@ public class PackageParser { } public void setApplicationVolumeUuid(String volumeUuid) { + final UUID storageUuid = StorageManager.convert(volumeUuid); this.applicationInfo.volumeUuid = volumeUuid; + this.applicationInfo.storageUuid = storageUuid; if (childPackages != null) { final int packageCount = childPackages.size(); for (int i = 0; i < packageCount; i++) { childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; + childPackages.get(i).applicationInfo.storageUuid = storageUuid; } } } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index e8e989f20ef7..f61032ef8250 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -290,7 +290,8 @@ public final class CameraManager { cameraId, callback, handler, - characteristics); + characteristics, + mContext.getApplicationInfo().targetSdkVersion); ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index e75b3758a31e..ab87f15d8794 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -36,6 +36,7 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.SubmitInfo; import android.hardware.camera2.utils.SurfaceUtils; import android.hardware.ICameraService; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -118,6 +119,8 @@ public class CameraDeviceImpl extends CameraDevice private CameraCaptureSessionCore mCurrentSession; private int mNextSessionId = 0; + private final int mAppTargetSdkVersion; + // Runnables for all state transitions, except error, which needs the // error code argument @@ -234,7 +237,7 @@ public class CameraDeviceImpl extends CameraDevice }; public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler, - CameraCharacteristics characteristics) { + CameraCharacteristics characteristics, int appTargetSdkVersion) { if (cameraId == null || callback == null || handler == null || characteristics == null) { throw new IllegalArgumentException("Null argument given"); } @@ -242,6 +245,7 @@ public class CameraDeviceImpl extends CameraDevice mDeviceCallback = callback; mDeviceHandler = handler; mCharacteristics = characteristics; + mAppTargetSdkVersion = appTargetSdkVersion; final int MAX_TAG_LEN = 23; String tag = String.format("CameraDevice-JV-%s", mCameraId); @@ -671,6 +675,16 @@ public class CameraDeviceImpl extends CameraDevice } } + private void overrideEnableZsl(CameraMetadataNative request, boolean newValue) { + Boolean enableZsl = request.get(CaptureRequest.CONTROL_ENABLE_ZSL); + if (enableZsl == null) { + // If enableZsl is not available, don't override. + return; + } + + request.set(CaptureRequest.CONTROL_ENABLE_ZSL, newValue); + } + @Override public CaptureRequest.Builder createCaptureRequest(int templateType) throws CameraAccessException { @@ -681,6 +695,13 @@ public class CameraDeviceImpl extends CameraDevice templatedRequest = mRemoteDevice.createDefaultRequest(templateType); + // If app target SDK is older than O, or it's not a still capture template, enableZsl + // must be false in the default request. + if (mAppTargetSdkVersion < Build.VERSION_CODES.O || + templateType != TEMPLATE_STILL_CAPTURE) { + overrideEnableZsl(templatedRequest, false); + } + CaptureRequest.Builder builder = new CaptureRequest.Builder( templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 9b5ff29d592e..167c46d6ded0 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -25,6 +25,7 @@ import android.util.SparseArray; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * A mapping from String keys to various {@link Parcelable} values. @@ -476,6 +477,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Inserts a UUID value into the mapping of this Bundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a UUID object, or null + */ + public void putUuid(@Nullable String key, @Nullable UUID value) { + unparcel(); + mMap.put(key, value); + } + + /** * Inserts an array of Parcelable values into the mapping of this Bundle, * replacing any existing value for the given key. Either key or value may * be null. @@ -858,6 +871,26 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * value is explicitly associated with the key. * * @param key a String, or null + * @return a UUID value, or null + */ + @Nullable + public UUID getUuid(@Nullable String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (UUID) o; + } catch (ClassCastException e) { + typeWarning(key, o, "UUID", e); + return null; + } + } + + /** + * Returns the value associated with the given key, or null if + * no mapping of the desired type exists for the given key or a null + * value is explicitly associated with the key. + * + * @param key a String, or null * @return a Bundle value, or null */ @Nullable diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index c3836a38c822..c1647c74f363 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -16,8 +16,6 @@ package android.os; -import android.annotation.IntegerRes; -import android.annotation.NonNull; import android.annotation.Nullable; import android.text.TextUtils; import android.util.ArrayMap; @@ -29,6 +27,9 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; +import dalvik.annotation.optimization.FastNative; +import dalvik.system.VMRuntime; + import libcore.util.SneakyThrow; import java.io.ByteArrayInputStream; @@ -49,9 +50,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; - -import dalvik.annotation.optimization.FastNative; -import dalvik.system.VMRuntime; +import java.util.UUID; /** * Container for a message (data and object references) that can @@ -243,6 +242,7 @@ public final class Parcel { private static final int VAL_SIZE = 26; private static final int VAL_SIZEF = 27; private static final int VAL_DOUBLEARRAY = 28; + private static final int VAL_UUID = 29; // The initial int32 in a Binder call's reply Parcel header: // Keep these in sync with libbinder's binder/Status.h. @@ -831,6 +831,15 @@ public final class Parcel { } /** + * Flatten a UUID into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. + */ + public final void writeUuid(UUID val) { + writeLong(val.getMostSignificantBits()); + writeLong(val.getLeastSignificantBits()); + } + + /** * Flatten a List into the parcel at the current dataPosition(), growing * dataCapacity() if needed. The List values are written using * {@link #writeValue} and must follow the specification there. @@ -1678,6 +1687,9 @@ public final class Parcel { } else if (v instanceof double[]) { writeInt(VAL_DOUBLEARRAY); writeDoubleArray((double[]) v); + } else if (v instanceof UUID) { + writeInt(VAL_UUID); + writeUuid((UUID) v); } else { Class<?> clazz = v.getClass(); if (clazz.isArray() && clazz.getComponentType() == Object.class) { @@ -2182,6 +2194,13 @@ public final class Parcel { } /** + * Read a UUID from the parcel at the current dataPosition(). + */ + public final UUID readUuid() { + return new UUID(readLong(), readLong()); + } + + /** * Read and return a byte[] object from the parcel. */ public final byte[] createByteArray() { @@ -2731,6 +2750,9 @@ public final class Parcel { case VAL_DOUBLEARRAY: return createDoubleArray(); + case VAL_UUID: + return readUuid(); + default: int off = dataPosition() - 4; throw new RuntimeException( diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index b5af766fd159..394253173553 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -66,6 +66,7 @@ import com.android.internal.util.Preconditions; import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -77,6 +78,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @@ -117,19 +119,66 @@ public class StorageManager { public static final String UUID_PRIVATE_INTERNAL = null; /** {@hide} */ public static final String UUID_PRIMARY_PHYSICAL = "primary_physical"; + /** {@hide} */ + public static final String UUID_SYSTEM = "system"; + // NOTE: UUID constants below are namespaced + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system /** - * Activity Action: Allows the user to manage their storage. This activity provides the ability - * to free up space on the device by deleting data such as apps. + * UUID representing the default internal storage of this device which + * provides {@link Environment#getDataDirectory()}. * <p> - * Input: Nothing. + * This value is constant across all devices and it will never change, and + * thus it cannot be used to uniquely identify a particular physical device. + * + * @see #getUuidForPath(File) + */ + public static final UUID UUID_DEFAULT = UUID + .fromString("41217664-9172-527a-b3d5-edabb50a7d69"); + + /** {@hide} */ + public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID + .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd"); + + /** {@hide} */ + public static final UUID UUID_SYSTEM_ = UUID + .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0"); + + /** + * Activity Action: Allows the user to manage their storage. This activity + * provides the ability to free up space on the device by deleting data such + * as apps. * <p> - * Output: Nothing. + * If the sending application has a specific storage device or allocation + * size in mind, they can optionally define {@link #EXTRA_UUID} or + * {@link #EXTRA_REQUESTED_BYTES}, respectively. */ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_MANAGE_STORAGE - = "android.os.storage.action.MANAGE_STORAGE"; + public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + + /** + * Extra {@link UUID} used to indicate the storage volume where an + * application is interested in allocating or managing disk space. + * + * @see #ACTION_MANAGE_STORAGE + * @see #UUID_DEFAULT + * @see #getUuidForPath(File) + */ + public static final String EXTRA_UUID = "android.os.storage.extra.UUID"; + + /** + * Extra used to indicate the total size (in bytes) that an application is + * interested in allocating. + * <p> + * When defined, the management UI will help guide the user to free up + * enough disk space to reach this requested value. + * + * @see #ACTION_MANAGE_STORAGE + */ + public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; /** {@hide} */ public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0; @@ -668,34 +717,44 @@ public class StorageManager { } } - /** {@hide} */ - public @Nullable String findUuidForPath(File path) { + /** + * Return a UUID identifying the storage volume that hosts the given + * filesystem path. + * <p> + * If this path is hosted by the default internal storage of the device at + * {@link Environment#getDataDirectory()}, the returned value will be + * {@link #UUID_DEFAULT}. + * + * @throws IOException when the storage device at the given path isn't + * present, or when it doesn't have a valid UUID. + */ + public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException { Preconditions.checkNotNull(path); final String pathString = path.getAbsolutePath(); if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) { - return StorageManager.UUID_PRIVATE_INTERNAL; + return UUID_DEFAULT; } try { for (VolumeInfo vol : mStorageManager.getVolumes(0)) { if (vol.path != null && FileUtils.contains(vol.path, pathString)) { // TODO: verify that emulated adopted devices have UUID of // underlying volume - return vol.fsUuid; + return convert(vol.fsUuid); } } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - throw new IllegalStateException("Failed to find a storage device for " + path); + throw new FileNotFoundException("Failed to find a storage device for " + path); } /** {@hide} */ - public @Nullable File findPathForUuid(String volumeUuid) { + public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException { final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid); if (vol != null) { return vol.getPath(); } - throw new IllegalStateException("Failed to find a storage device for " + volumeUuid); + throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid); } /** {@hide} */ @@ -1451,7 +1510,7 @@ public class StorageManager { /** * Return quota size in bytes for all cached data belonging to the calling - * app on the filesystem that hosts the given path. + * app on the given storage volume. * <p> * If your app goes above this quota, your cached files will be some of the * first to be deleted when additional disk space is needed. Conversely, if @@ -1466,21 +1525,34 @@ public class StorageManager { * as a single unit. * </p> * - * @see #getCacheSizeBytes(File) + * @param storageUuid the UUID of the storage volume that you're interested + * in. The UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support cache quotas. + * @see #getCacheSizeBytes(UUID) */ - public long getCacheQuotaBytes(File path) { + public long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException { try { - final String volumeUuid = findUuidForPath(path); final ApplicationInfo app = mContext.getApplicationInfo(); - return mStorageManager.getCacheQuotaBytes(volumeUuid, app.uid); + return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getCacheQuotaBytes(@NonNull File path) throws IOException { + return getCacheQuotaBytes(getUuidForPath(path)); + } + /** * Return total size in bytes of all cached data belonging to the calling - * app on the filesystem that hosts the given path. + * app on the given storage volume. * <p> * Cached data tracked by this method always includes * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and @@ -1493,13 +1565,20 @@ public class StorageManager { * as a single unit. * </p> * - * @see #getCacheQuotaBytes() + * @param storageUuid the UUID of the storage volume that you're interested + * in. The UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support cache quotas. + * @see #getCacheQuotaBytes(UUID) */ - public long getCacheSizeBytes(File path) { + public long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException { try { - final String volumeUuid = findUuidForPath(path); final ApplicationInfo app = mContext.getApplicationInfo(); - return mStorageManager.getCacheSizeBytes(volumeUuid, app.uid); + return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1507,25 +1586,31 @@ public class StorageManager { /** @removed */ @Deprecated - public long getCacheQuotaBytes() { + public long getCacheSizeBytes(@NonNull File path) throws IOException { + return getCacheSizeBytes(getUuidForPath(path)); + } + + /** @removed */ + @Deprecated + public long getCacheQuotaBytes() throws IOException { return getCacheQuotaBytes(mContext.getCacheDir()); } /** @removed */ @Deprecated - public long getCacheSizeBytes() { + public long getCacheSizeBytes() throws IOException { return getCacheSizeBytes(mContext.getCacheDir()); } /** @removed */ @Deprecated - public long getExternalCacheQuotaBytes() { + public long getExternalCacheQuotaBytes() throws IOException { return getCacheQuotaBytes(mContext.getExternalCacheDir()); } /** @removed */ @Deprecated - public long getExternalCacheSizeBytes() { + public long getExternalCacheSizeBytes() throws IOException { return getCacheSizeBytes(mContext.getExternalCacheDir()); } @@ -1542,8 +1627,8 @@ public class StorageManager { * this flag to take effect. * </p> * - * @see #getAllocatableBytes(File, int) - * @see #allocateBytes(File, long, int) + * @see #getAllocatableBytes(UUID, int) + * @see #allocateBytes(UUID, long, int) * @see #allocateBytes(FileDescriptor, long, int) */ @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) @@ -1558,32 +1643,43 @@ public class StorageManager { /** * Return the maximum number of new bytes that your app can allocate for - * itself using {@link #allocateBytes(File, long, int)} at the given path. - * This value is typically larger than {@link File#getUsableSpace()}, since - * the system may be willing to delete cached files to satisfy an allocation - * request. + * itself on the given storage volume. This value is typically larger than + * {@link File#getUsableSpace()}, since the system may be willing to delete + * cached files to satisfy an allocation request. You can then allocate + * space for yourself using {@link #allocateBytes(UUID, long, int)} or + * {@link #allocateBytes(FileDescriptor, long, int)}. * <p> * This method is best used as a pre-flight check, such as deciding if there * is enough space to store an entire music album before you allocate space * for each audio file in the album. Attempts to allocate disk space beyond * the returned value will fail. + * <p> + * If the returned value is not large enough for the data you'd like to + * store, you can launch {@link #ACTION_MANAGE_STORAGE} with the + * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help + * involve the user in freeing up disk space. * <p class="note"> * Note: if your app uses the {@code android:sharedUserId} manifest feature, * then allocatable space for all packages in your shared UID is tracked * together as a single unit. * </p> * - * @param path the path where you're considering allocating disk space, - * since allocatable space can vary widely depending on the - * underlying storage device. + * @param storageUuid the UUID of the storage volume where you're + * considering allocating disk space, since allocatable space can + * vary widely depending on the underlying storage device. The + * UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. * @param flags to apply to the request. * @return the maximum number of new bytes that the calling app can allocate - * using {@link #allocateBytes(File, long, int)}. + * using {@link #allocateBytes(UUID, long, int)} or + * {@link #allocateBytes(FileDescriptor, long, int)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space. */ - public long getAllocatableBytes(File path, @AllocateFlags int flags) throws IOException { + public long getAllocatableBytes(@NonNull UUID storageUuid, @AllocateFlags int flags) + throws IOException { try { - final String volumeUuid = findUuidForPath(path); - return mStorageManager.getAllocatableBytes(volumeUuid, flags); + return mStorageManager.getAllocatableBytes(convert(storageUuid), flags); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); throw new RuntimeException(e); @@ -1592,28 +1688,40 @@ public class StorageManager { } } + /** @removed */ + @Deprecated + public long getAllocatableBytes(@NonNull File path, @AllocateFlags int flags) + throws IOException { + return getAllocatableBytes(getUuidForPath(path), flags); + } + /** - * Allocate the requested number of bytes for your application to use at the - * given path. This will cause the system to delete any cached files - * necessary to satisfy your request. + * Allocate the requested number of bytes for your application to use on the + * given storage volume. This will cause the system to delete any cached + * files necessary to satisfy your request. * <p> * Attempts to allocate disk space beyond the value returned by - * {@link #getAllocatableBytes(File, int)} will fail. + * {@link #getAllocatableBytes(UUID, int)} will fail. * <p> * Since multiple apps can be running simultaneously, this method may be * subject to race conditions. If possible, consider using * {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee * that bytes are allocated to an opened file. * - * @param path the path where you'd like to allocate disk space. + * @param storageUuid the UUID of the storage volume where you'd like to + * allocate disk space. The UUID for a specific path can be + * obtained using {@link #getUuidForPath(File)}. * @param bytes the number of bytes to allocate. * @param flags to apply to the request. - * @see #getAllocatableBytes(File, int) + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space, or if the device had + * trouble allocating the requested space. + * @see #getAllocatableBytes(UUID, int) */ - public void allocateBytes(File path, long bytes, @AllocateFlags int flags) throws IOException { + public void allocateBytes(@NonNull UUID storageUuid, long bytes, @AllocateFlags int flags) + throws IOException { try { - final String volumeUuid = findUuidForPath(path); - mStorageManager.allocateBytes(volumeUuid, bytes, flags); + mStorageManager.allocateBytes(convert(storageUuid), bytes, flags); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); } catch (RemoteException e) { @@ -1621,13 +1729,20 @@ public class StorageManager { } } + /** @removed */ + @Deprecated + public void allocateBytes(@NonNull File path, long bytes, @AllocateFlags int flags) + throws IOException { + allocateBytes(getUuidForPath(path), bytes, flags); + } + /** * Allocate the requested number of bytes for your application to use in the * given open file. This will cause the system to delete any cached files * necessary to satisfy your request. * <p> * Attempts to allocate disk space beyond the value returned by - * {@link #getAllocatableBytes(File, int)} will fail. + * {@link #getAllocatableBytes(UUID, int)} will fail. * <p> * This method guarantees that bytes have been allocated to the opened file, * otherwise it will throw if fast allocation is not possible. Fast @@ -1636,9 +1751,15 @@ public class StorageManager { * * @param fd the open file that you'd like to allocate disk space for. * @param bytes the number of bytes to allocate. This is the desired final - * size of the open file. + * size of the open file. If the open file is smaller than this + * requested size, it will be extended without modifying any + * existing contents. If the open file is larger than this + * requested size, it will be truncated. * @param flags to apply to the request. - * @see #getAllocatableBytes(File, int) + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space, or if the device had + * trouble allocating the requested space. + * @see #getAllocatableBytes(UUID, int) * @see Environment#isExternalStorageEmulated(File) */ public void allocateBytes(FileDescriptor fd, long bytes, @AllocateFlags int flags) @@ -1777,6 +1898,32 @@ public class StorageManager { return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE); } + /** {@hide} */ + public static UUID convert(String uuid) { + if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) { + return UUID_DEFAULT; + } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) { + return UUID_PRIMARY_PHYSICAL_; + } else if (Objects.equals(uuid, UUID_SYSTEM)) { + return UUID_SYSTEM_; + } else { + return UUID.fromString(uuid); + } + } + + /** {@hide} */ + public static String convert(UUID storageUuid) { + if (UUID_DEFAULT.equals(storageUuid)) { + return UUID_PRIVATE_INTERNAL; + } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) { + return UUID_PRIMARY_PHYSICAL; + } else if (UUID_SYSTEM_.equals(storageUuid)) { + return UUID_SYSTEM; + } else { + return storageUuid.toString(); + } + } + private final Object mFuseAppLoopLock = new Object(); @GuardedBy("mFuseAppLoopLock") diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 539559d19c82..c6ea9586374d 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8330,7 +8330,6 @@ public final class Settings { * enabled state. * @hide */ - @SystemApi public static final String NETWORK_RECOMMENDATIONS_ENABLED = "network_recommendations_enabled"; diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 258d257813ca..7f960dff0bdf 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -21,6 +21,7 @@ import static android.view.autofill.Helper.DEBUG; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.assist.AssistStructure; import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; @@ -158,6 +159,7 @@ public final class SaveInfo implements Parcelable { private final AutofillId[] mRequiredIds; private final AutofillId[] mOptionalIds; private final CharSequence mDescription; + private final boolean mSaveOnAllViewsInvisible; private SaveInfo(Builder builder) { mType = builder.mType; @@ -166,6 +168,7 @@ public final class SaveInfo implements Parcelable { mRequiredIds = builder.mRequiredIds; mOptionalIds = builder.mOptionalIds; mDescription = builder.mDescription; + mSaveOnAllViewsInvisible = builder.mSaveOnAllViewsInvisible; } /** @hide */ @@ -194,6 +197,11 @@ public final class SaveInfo implements Parcelable { } /** @hide */ + public boolean saveOnAllViewsInvisible() { + return mSaveOnAllViewsInvisible; + } + + /** @hide */ public CharSequence getDescription() { return mDescription; } @@ -211,6 +219,7 @@ public final class SaveInfo implements Parcelable { private AutofillId[] mOptionalIds; private CharSequence mDescription; private boolean mDestroyed; + private boolean mSaveOnAllViewsInvisible; /** * Creates a new builder. @@ -259,6 +268,21 @@ public final class SaveInfo implements Parcelable { } /** + * Usually {@link AutofillService#onSaveRequest(AssistStructure, Bundle, SaveCallback)} + * is called once the activity finishes. If this property is set it is called once all + * autofillable or saved views become invisible. + * + * @param saveOnAllViewsInvisible Set to {@code true} if the data should be saved once + * all the views become invisible. + * @return This builder. + */ + public @NonNull Builder setSaveOnAllViewsInvisible(boolean saveOnAllViewsInvisible) { + throwIfDestroyed(); + mSaveOnAllViewsInvisible = saveOnAllViewsInvisible; + return this; + } + + /** * Sets the ids of additional, optional views the service would be interested to save. * * <p>See {@link SaveInfo} for more info. @@ -354,6 +378,7 @@ public final class SaveInfo implements Parcelable { .append(", requiredIds=").append(Arrays.toString(mRequiredIds)) .append(", optionalIds=").append(Arrays.toString(mOptionalIds)) .append(", description=").append(mDescription) + .append(", saveOnNoVisibleTrackedViews=").append(mSaveOnAllViewsInvisible) .append("]").toString(); } @@ -374,6 +399,7 @@ public final class SaveInfo implements Parcelable { parcel.writeParcelable(mNegativeActionListener, flags); parcel.writeParcelableArray(mOptionalIds, flags); parcel.writeCharSequence(mDescription); + parcel.writeBoolean(mSaveOnAllViewsInvisible); } public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() { @@ -387,6 +413,7 @@ public final class SaveInfo implements Parcelable { builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null)); builder.setOptionalIds(parcel.readParcelableArray(null, AutofillId.class)); builder.setDescription(parcel.readCharSequence()); + builder.setSaveOnAllViewsInvisible(parcel.readBoolean()); return builder.build(); } diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index dc1a70d74d7f..ed44f2599695 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -18,6 +18,7 @@ package android.service.notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.os.UserHandle; import android.service.notification.IStatusBarNotificationHolder; import android.service.notification.StatusBarNotification; import android.service.notification.NotificationRankingUpdate; @@ -36,8 +37,8 @@ oneway interface INotificationListener void onInterruptionFilterChanged(int interruptionFilter); // companion device managers only - void onNotificationChannelModification(String pkgName, in NotificationChannel channel, int modificationType); - void onNotificationChannelGroupModification(String pkgName, in NotificationChannelGroup group, int modificationType); + void onNotificationChannelModification(String pkgName, in UserHandle user, in NotificationChannel channel, int modificationType); + void onNotificationChannelGroupModification(String pkgName, in UserHandle user, in NotificationChannelGroup group, int modificationType); // rankers only void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 4833be335c88..00bd30456c9e 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -49,6 +49,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -231,25 +232,25 @@ public abstract class NotificationListenerService extends Service { /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was created. + * {@link #onNotificationChannelModified(String, UserHandle,NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was created. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was updated. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle,NotificationChannelGroup, int)} + * - the provided object was updated. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was deleted. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was deleted. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; @@ -432,13 +433,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the channel belongs to. + * @param user The user on which the change was made. * @param channel The channel that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelModified(String pkg, NotificationChannel channel, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelModified(String pkg, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -449,13 +451,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the group belongs to. + * @param user The user on which the change was made. * @param group The group that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelGroupModified(String pkg, NotificationChannelGroup group, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelGroupModified(String pkg, UserHandle user, + NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -661,21 +664,24 @@ public abstract class NotificationListenerService extends Service { /** - * Updates a notification channel for a given package. This should only be used to reflect - * changes a user has made to the channel via the listener's user interface. + * Updates a notification channel for a given package for a given user. This should only be used + * to reflect changes a user has made to the channel via the listener's user interface. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package the channel belongs to. + * @param user The user the channel belongs to. * @param channel the channel to update. */ - public final void updateNotificationChannel(@NonNull String pkg, + public final void updateNotificationChannel(@NonNull String pkg, @NonNull UserHandle user, @NonNull NotificationChannel channel) { if (!isBound()) return; try { getNotificationInterface().updateNotificationChannelFromPrivilegedListener( - mWrapper, pkg, channel); + mWrapper, pkg, user, channel); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -683,19 +689,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channels belonging to the given package. + * Returns all notification channels belonging to the given package for a given user. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channels for. */ - public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg) { + public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -703,19 +712,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channel groups belonging to the given package. + * Returns all notification channel groups belonging to the given package for a given user. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channel groups for. */ - public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg) { + public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelGroupsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -1252,24 +1264,27 @@ public abstract class NotificationListenerService extends Service { } @Override - public void onNotificationChannelModification(String pkgName, NotificationChannel channel, + public void onNotificationChannelModification(String pkgName, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = channel; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = channel; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_MODIFIED, args).sendToTarget(); } @Override - public void onNotificationChannelGroupModification(String pkgName, + public void onNotificationChannelGroupModification(String pkgName, UserHandle user, NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = group; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = group; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget(); } @@ -1841,17 +1856,19 @@ public abstract class NotificationListenerService extends Service { case MSG_ON_NOTIFICATION_CHANNEL_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannel channel = (NotificationChannel) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelModified(pkgName, channel, modificationType); + UserHandle user= (UserHandle) args.arg2; + NotificationChannel channel = (NotificationChannel) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelModified(pkgName, user, channel, modificationType); } break; case MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannelGroup group = (NotificationChannelGroup) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelGroupModified(pkgName, group, modificationType); + UserHandle user = (UserHandle) args.arg2; + NotificationChannelGroup group = (NotificationChannelGroup) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelGroupModified(pkgName, user, group, modificationType); } break; } } diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl index 2fe98c0b6f05..dbeb747adfba 100644 --- a/core/java/android/view/IPinnedStackController.aidl +++ b/core/java/android/view/IPinnedStackController.aidl @@ -28,4 +28,9 @@ interface IPinnedStackController { * Notifies the controller that the PiP is currently minimized. */ oneway void setIsMinimized(boolean isMinimized); + + /** + * @return what WM considers to be the current device rotation. + */ + int getDisplayRotation(); } diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 782f3499fb79..9382741a81ec 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -41,9 +41,13 @@ oneway interface IPinnedStackListener { * current state with the aspect ratio applied. The {@param animatingBounds} are provided * to indicate the current target bounds of the pinned stack (the final bounds if animating, * the current bounds if not), which may be helpful in calculating dependent animation bounds. + * + * The {@param displayRotation} is provided so that the client can verify when making certain + * calls that it will not provide stale information based on an old display rotation (ie. if + * the WM has changed in the mean time but the client has not received onMovementBoundsChanged). */ void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds, - boolean fromImeAdjustement); + boolean fromImeAdjustement, int displayRotation); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 172ad8da5381..7d2d77e251a9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -66,6 +66,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -4380,6 +4381,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Nullable private RoundScrollbarRenderer mRoundScrollbarRenderer; + /** Used to delay visibility updates sent to the autofill manager */ + private Handler mVisibilityChangeForAutofillHandler; + /** * Simple constructor to use when creating a view from code. * @@ -11696,6 +11700,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (fg != null && isVisible != fg.isVisible()) { fg.setVisible(isVisible, false); } + + if (isAutofillable()) { + AutofillManager afm = getAutofillManager(); + + if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) { + if (mVisibilityChangeForAutofillHandler != null) { + mVisibilityChangeForAutofillHandler.removeMessages(0); + } + + // If the view is in the background but still part of the hierarchy this is called + // with isVisible=false. Hence visibility==false requires further checks + if (isVisible) { + afm.notifyViewVisibilityChange(this, true); + } else { + if (mVisibilityChangeForAutofillHandler == null) { + mVisibilityChangeForAutofillHandler = + new VisibilityChangeForAutofillHandler(afm, this); + } + // Let current operation (e.g. removal of the view from the hierarchy) + // finish before checking state + mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); + } + } + } } /** @@ -24492,6 +24520,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * When a view becomes invisible checks if autofill considers the view invisible too. This + * happens after the regular removal operation to make sure the operation is finished by the + * time this is called. + */ + private static class VisibilityChangeForAutofillHandler extends Handler { + private final AutofillManager mAfm; + private final View mView; + + private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, + @NonNull View view) { + mAfm = afm; + mView = view; + } + + @Override + public void handleMessage(Message msg) { + mAfm.notifyViewVisibilityChange(mView, mView.isShown()); + } + } + + /** * Base class for derived classes that want to save and restore their own * state in {@link android.view.View#onSaveInstanceState()}. */ diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index ec6559cba39b..f9f400d83b09 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -32,6 +32,7 @@ import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.View; @@ -143,6 +144,10 @@ public final class AutofillManager { @GuardedBy("mLock") @Nullable private ParcelableMap mLastAutofilledData; + /** If view tracking is enabled, contains the tracking state */ + @GuardedBy("mLock") + @Nullable private TrackedViews mTrackedViews; + /** @hide */ public interface AutofillClient { /** @@ -177,6 +182,20 @@ public final class AutofillManager { * @return Whether the UI was hidden. */ boolean autofillCallbackRequestHideFillUi(); + + /** + * Checks if the view is currently attached and visible. + * + * @return {@code true} iff the view is attached or visible + */ + boolean getViewVisibility(int viewId); + + /** + * Checks is the client is currently visible as understood by autofill. + * + * @return {@code true} if the client is currently visible + */ + boolean isVisibleForAutofill(); } /** @@ -260,6 +279,21 @@ public final class AutofillManager { } /** + * Called once the client becomes visible. + * + * @see AutofillClient#isVisibleForAutofill() + * + * {@hide} + */ + public void onVisibleForAutofill() { + synchronized (mLock) { + if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) { + mTrackedViews.onVisibleForAutofill(); + } + } + } + + /** * Save state before activity lifecycle * * @param outState Place to store the state @@ -412,6 +446,22 @@ public final class AutofillManager { } /** + * Called when a {@link View view's} visibility changes. + * + * @param view {@link View} that was exited. + * @param isVisible visible if the view is visible in the view hierarchy. + * + * @hide + */ + public void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) { + synchronized (mLock) { + if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) { + mTrackedViews.notifyViewVisibilityChange(view, isVisible); + } + } + } + + /** * Called when a virtual view that supports autofill is entered. * * @param view the {@link View} whose descendant is the virtual view. @@ -669,6 +719,7 @@ public final class AutofillManager { throw e.rethrowFromSystemServer(); } + mTrackedViews = null; mSessionId = NO_SESSION; } @@ -683,6 +734,7 @@ public final class AutofillManager { throw e.rethrowFromSystemServer(); } + mTrackedViews = null; mSessionId = NO_SESSION; } @@ -903,6 +955,25 @@ public final class AutofillManager { } } + /** + * Set the tracked views. + * + * @param trackedIds The views to be tracked + * @param saveOnAllViewsInvisible Finish the session once all tracked views are invisible. + */ + private void setTrackedViews(int sessionId, List<AutofillId> trackedIds, + boolean saveOnAllViewsInvisible) { + synchronized (mLock) { + if (mEnabled && mSessionId == sessionId) { + if (saveOnAllViewsInvisible) { + mTrackedViews = new TrackedViews(trackedIds); + } else { + mTrackedViews = null; + } + } + } + } + private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) { final View anchor = findAchorView(windowToken, id); @@ -969,6 +1040,195 @@ public final class AutofillManager { } /** + * View tracking information. Once all tracked views become invisible the session is finished. + */ + private class TrackedViews { + /** Visible tracked views */ + @Nullable private ArraySet<AutofillId> mVisibleTrackedIds; + + /** Invisible tracked views */ + @Nullable private ArraySet<AutofillId> mInvisibleTrackedIds; + + /** + * Check if set is null or value is in set. + * + * @param set The set or null (== empty set) + * @param value The value that might be in the set + * + * @return {@code true} iff set is not empty and value is in set + */ + private <T> boolean isInSet(@Nullable ArraySet<T> set, T value) { + return set != null && set.contains(value); + } + + /** + * Add a value to a set. If set is null, create a new set. + * + * @param set The set or null (== empty set) + * @param valueToAdd The value to add + * + * @return The set including the new value. If set was {@code null}, a set containing only + * the new value. + */ + @NonNull + private <T> ArraySet<T> addToSet(@Nullable ArraySet<T> set, T valueToAdd) { + if (set == null) { + set = new ArraySet<>(1); + } + + set.add(valueToAdd); + + return set; + } + + /** + * Remove a value from a set. + * + * @param set The set or null (== empty set) + * @param valueToRemove The value to remove + * + * @return The set without the removed value. {@code null} if set was null, or is empty + * after removal. + */ + @Nullable + private <T> ArraySet<T> removeFromSet(@Nullable ArraySet<T> set, T valueToRemove) { + if (set == null) { + return null; + } + + set.remove(valueToRemove); + + if (set.isEmpty()) { + return null; + } + + return set; + } + + /** + * Set the tracked views. + * + * @param trackedIds The views to be tracked + */ + TrackedViews(@NonNull List<AutofillId> trackedIds) { + mVisibleTrackedIds = null; + mInvisibleTrackedIds = null; + + AutofillClient client = getClientLocked(); + if (trackedIds != null) { + int numIds = trackedIds.size(); + for (int i = 0; i < numIds; i++) { + AutofillId id = trackedIds.get(i); + + boolean isVisible = true; + if (client != null && client.isVisibleForAutofill()) { + isVisible = client.getViewVisibility(id.getViewId()); + } + + if (isVisible) { + mVisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } else { + mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } + } + } + + if (DEBUG) { + Log.d(TAG, "TrackedViews(trackedIds=" + trackedIds + "): " + + " mVisibleTrackedIds=" + mVisibleTrackedIds + + " mInvisibleTrackedIds=" + mInvisibleTrackedIds); + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + + /** + * Called when a {@link View view's} visibility changes. + * + * @param view {@link View} that was exited. + * @param isVisible visible if the view is visible in the view hierarchy. + */ + void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) { + AutofillId id = getAutofillId(view); + AutofillClient client = getClientLocked(); + + if (DEBUG) { + Log.d(TAG, "notifyViewVisibilityChange(): id=" + id + " isVisible=" + + isVisible); + } + + if (client != null && client.isVisibleForAutofill()) { + if (isVisible) { + if (isInSet(mInvisibleTrackedIds, id)) { + mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id); + mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id); + } + } else { + if (isInSet(mVisibleTrackedIds, id)) { + mVisibleTrackedIds = removeFromSet(mVisibleTrackedIds, id); + mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } + } + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + + /** + * Called once the client becomes visible. + * + * @see AutofillClient#isVisibleForAutofill() + */ + void onVisibleForAutofill() { + // The visibility of the views might have changed while the client was not started, + // hence update the visibility state for all views. + AutofillClient client = getClientLocked(); + ArraySet<AutofillId> updatedVisibleTrackedIds = null; + ArraySet<AutofillId> updatedInvisibleTrackedIds = null; + if (client != null) { + if (mInvisibleTrackedIds != null) { + for (AutofillId id : mInvisibleTrackedIds) { + if (client.getViewVisibility(id.getViewId())) { + updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); + + if (DEBUG) { + Log.i(TAG, "onVisibleForAutofill() " + id + " became visible"); + } + } else { + updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); + } + } + } + + if (mVisibleTrackedIds != null) { + for (AutofillId id : mVisibleTrackedIds) { + if (client.getViewVisibility(id.getViewId())) { + updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); + } else { + updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); + + if (DEBUG) { + Log.i(TAG, "onVisibleForAutofill() " + id + " became invisible"); + } + } + } + } + + mInvisibleTrackedIds = updatedInvisibleTrackedIds; + mVisibleTrackedIds = updatedVisibleTrackedIds; + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + } + + /** * Callback for auto-fill related events. * * <p>Typically used for applications that display their own "auto-complete" views, so they can @@ -1106,5 +1366,16 @@ public final class AutofillManager { }); } } + + @Override + public void setTrackedViews(int sessionId, List<AutofillId> ids, + boolean saveOnAllViewsInvisible) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.mContext.getMainThreadHandler().post( + () -> afm.setTrackedViews(sessionId, ids, saveOnAllViewsInvisible) + ); + } + } } } diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 56f91ed6de9b..1a6bad2d1cd6 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -49,6 +49,13 @@ oneway interface IAutoFillManagerClient { void authenticate(int sessionId, in IntentSender intent, in Intent fillInIntent); /** + * Sets the views to track. If saveOnAllViewsInvisible is set and all these view are invisible + * the session is finished automatically. + */ + void setTrackedViews(int sessionId, in List<AutofillId> ids, + boolean saveOnAllViewsInvisible); + + /** * Requests showing the fill UI. */ void requestShowFillUi(int sessionId, in IBinder windowToken, in AutofillId id, int width, diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index 6c6079f202fd..d11c03ad6878 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -17,11 +17,13 @@ package android.widget; import android.content.Context; +import android.content.Intent; import android.content.res.TypedArray; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; +import android.net.Uri; import android.os.SystemClock; import android.text.format.DateUtils; import android.util.AttributeSet; @@ -148,6 +150,22 @@ public class Chronometer extends TextView { } /** + * @return whether this is the final countdown + */ + public boolean isTheFinalCountDown() { + try { + getContext().startActivity( + new Intent(Intent.ACTION_VIEW, Uri.parse("https://youtu.be/9jK-NcRmVcw")) + .addCategory(Intent.CATEGORY_BROWSABLE) + .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT + | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)); + return true; + } catch (Exception e) { + return false; + } + } + + /** * Set the time that the count-up timer is in reference to. * * @param base Use the {@link SystemClock#elapsedRealtime} time base. diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 520302ee02b9..2c7174d71c6b 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -24,6 +24,7 @@ #include <ScopedLocalRef.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_hardware_HardwareBuffer.h> +#include <vndk/hardware_buffer.h> #include <sensor/Sensor.h> #include <sensor/SensorEventQueue.h> #include <sensor/SensorManager.h> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 569646820402..95ba94209343 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2439,6 +2439,14 @@ <!-- Whether the given RRO is static or not. --> <attr name="isStatic" format="boolean" /> + <!-- Required property name/value pair used to enable this overlay. + e.g. name=ro.oem.sku value=MKT210. + Overlay will be ignored unless system property exists and is + set to specified value --> + <!-- @hide @SystemApi This shouldn't be public. --> + <attr name="requiredSystemPropertyName" format="string" /> + <!-- @hide @SystemApi This shouldn't be public. --> + <attr name="requiredSystemPropertyValue" format="string" /> </declare-styleable> <!-- Declaration of an {@link android.content.Intent} object in XML. May diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 213d6cafa72b..9e98efde2c73 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2817,6 +2817,10 @@ <public name="defaultFocusHighlightEnabled" /> <public name="persistentFeature"/> <public name="windowSplashscreenContent" /> + <!-- @hide @SystemApi --> + <public name="requiredSystemPropertyName" /> + <!-- @hide @SystemApi --> + <public name="requiredSystemPropertyValue" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/core/tests/overlaytests/OverlayAppFiltered/Android.mk b/core/tests/overlaytests/OverlayAppFiltered/Android.mk new file mode 100644 index 000000000000..8ba21df189f0 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_JAVA_LIBRARIES += legacy-test + +LOCAL_SDK_VERSION := system_current + +LOCAL_PACKAGE_NAME := com.android.overlaytest.filtered_app_overlay + +include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml new file mode 100644 index 000000000000..5b7950a25fbf --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml @@ -0,0 +1,9 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.overlaytest.filtered_app_overlay" + android:versionCode="1" + android:versionName="1.0"> + <overlay android:targetPackage="com.android.overlaytest" + android:requiredSystemPropertyName="persist.oem.overlay.test" + android:requiredSystemPropertyValue="foo" + android:priority="3"/> +</manifest> diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt new file mode 100644 index 000000000000..0954cedeb5d5 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt @@ -0,0 +1 @@ +Lorem ipsum: filtered overlays. diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml b/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml new file mode 100644 index 000000000000..60b94eec5994 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="str">filtered</string> +</resources> diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml new file mode 100644 index 000000000000..e2652b7e2915 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<integer value="3"/> diff --git a/core/tests/overlaytests/OverlayAppFirst/Android.mk b/core/tests/overlaytests/OverlayAppFirst/Android.mk index ee991fcd919a..51f4487fb25f 100644 --- a/core/tests/overlaytests/OverlayAppFirst/Android.mk +++ b/core/tests/overlaytests/OverlayAppFirst/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/OverlayAppSecond/Android.mk b/core/tests/overlaytests/OverlayAppSecond/Android.mk index 87402c43dd9a..b3cfd1817cbf 100644 --- a/core/tests/overlaytests/OverlayAppSecond/Android.mk +++ b/core/tests/overlaytests/OverlayAppSecond/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk index 4767e52c0816..964348fab881 100644 --- a/core/tests/overlaytests/OverlayTest/Android.mk +++ b/core/tests/overlaytests/OverlayTest/Android.mk @@ -7,6 +7,8 @@ LOCAL_PACKAGE_NAME := OverlayTest LOCAL_DEX_PREOPT := false +LOCAL_JAVA_LIBRARIES += legacy-test + LOCAL_MODULE_PATH := $(TARGET_OUT)/app LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk index b1327f713ae7..5265d9169f7f 100644 --- a/core/tests/overlaytests/OverlayTestOverlay/Android.mk +++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py index 2aa25adeda5d..e88805e8cbf1 100755 --- a/core/tests/overlaytests/testrunner.py +++ b/core/tests/overlaytests/testrunner.py @@ -13,6 +13,7 @@ TASK_COMPILATION = 'compile' TASK_DISABLE_OVERLAYS = 'disable overlays' TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays' TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay' +TASK_ENABLE_FILTERED_OVERLAYS = 'enable filtered overlays' TASK_FILE_EXISTS_TEST = 'test (file exists)' TASK_GREP_IDMAP_TEST = 'test (grep idmap)' TASK_MD5_TEST = 'test (md5)' @@ -25,6 +26,7 @@ TASK_PUSH = 'push' TASK_ROOT = 'root' TASK_REMOUNT = 'remount' TASK_RM = 'rm' +TASK_SETPROP = 'setprop' TASK_SETUP_IDMAP_PATH = 'setup idmap --path' TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan' TASK_START = 'start' @@ -188,7 +190,10 @@ class PushTask: return "%s -> %s" % (self.src, self.dest) def execute(self): - src = os.getenv('OUT') + "/" + self.src + src = os.getenv('OUT') + if (src is None): + return 1, "", "Unable to proceed - $OUT environment var not set\n" + src += "/" + self.src argv = shlex.split(adb + ' push %s %s' % (src, self.dest)) proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = proc.communicate() @@ -219,10 +224,24 @@ class RmTask: def execute(self): returncode, stdout, stderr = _adb_shell('ls %s' % self.path) - if returncode != 0 and stdout.endswith(': No such file or directory\n'): + if returncode != 0 and stderr.endswith(': No such file or directory\n'): return 0, "", "" return _adb_shell('rm -r %s' % self.path) +class SetPropTask: + def __init__(self, prop, value): + self.prop = prop + self.value = value + + def get_type(self): + return TASK_SETPROP + + def get_name(self): + return self.prop + + def execute(self): + return _adb_shell('setprop %s %s' % (self.prop, self.value)) + class IdmapPathTask: def __init__(self, path_target_apk, path_overlay_apk, path_idmap): self.path_target_apk = path_target_apk @@ -236,7 +255,7 @@ class IdmapPathTask: return self.path_idmap def execute(self): - return _adb_shell('su system idmap --path "%s" "%s" "%s"' % (self.path_target_apk, self.path_overlay_apk, self.path_idmap)) + return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.target_pkg_name, self.target_pkg, self.idmap_dir, self.overlay_dir)) class IdmapScanTask: def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir): @@ -411,8 +430,12 @@ def _create_disable_overlays_task(): RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"), RmTask("/vendor/overlay/app_a.apk"), RmTask("/vendor/overlay/app_b.apk"), + RmTask("/vendor/overlay/app_c.apk"), RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"), RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"), + RmTask("/data/resource-cache/vendor@overlay@app_c.apk@idmap"), + SetPropTask('persist.oem.overlay.test', '""'), + RmTask("/data/property/persist.oem.overlay.test"), ] return CompoundTask(TASK_DISABLE_OVERLAYS, tasks) @@ -435,9 +458,23 @@ def _create_enable_multiple_overlays_task(): PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'), PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'), PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'), + PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'), ] return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks) +def _create_enable_filtered_overlays_task(): + tasks = [ + _create_disable_overlays_task(), + SetPropTask('persist.oem.overlay.test', 'foo'), + MkdirTask('/system/vendor'), + MkdirTask('/vendor/overlay'), + PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'), + PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'), + PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'), + PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'), + ] + return CompoundTask(TASK_ENABLE_FILTERED_OVERLAYS, tasks) + def _create_setup_idmap_path_task(idmaps, symlinks): tasks = [ _create_enable_single_overlay_task(), @@ -450,12 +487,11 @@ def _create_setup_idmap_path_task(idmaps, symlinks): def _create_setup_idmap_scan_task(idmaps, symlinks): tasks = [ - _create_enable_single_overlay_task(), + _create_enable_filtered_overlays_task(), RmTask(symlinks), RmTask(idmaps), MkdirTask(idmaps), MkdirTask(symlinks), - _create_enable_multiple_overlays_task(), ] return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks) @@ -538,7 +574,7 @@ def _create_opt_parser(): help='do not rebuild test projects') parser.add_option('-i', '--test-idmap', action='store_true', dest='test_idmap', default=False, - help='run tests for single overlay') + help='run tests for idmap') parser.add_option('-0', '--test-no-overlay', action='store_true', dest='test_no_overlay', default=False, help='run tests without any overlay') @@ -548,16 +584,21 @@ def _create_opt_parser(): parser.add_option('-2', '--test-multiple-overlays', action='store_true', dest='test_multiple_overlays', default=False, help='run tests for multiple overlays') + parser.add_option('-3', '--test-filtered-overlays', action='store_true', + dest='test_filtered_overlays', default=False, + help='run tests for filtered (sys prop) overlays') return parser if __name__ == '__main__': opt_parser = _create_opt_parser() opts, args = opt_parser.parse_args(sys.argv[1:]) - if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays: + if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays and not opts.test_filtered_overlays: opts.test_idmap = True opts.test_no_overlay = True opts.test_single_overlay = True opts.test_multiple_overlays = True + opts.test_filtered_overlays = True + if len(args) > 0: opt_parser.error("unexpected arguments: %s" % " ".join(args)) # will never reach this: opt_parser.error will call sys.exit @@ -580,6 +621,7 @@ if __name__ == '__main__': tasks.append(CompilationTask('OverlayTestOverlay/Android.mk')) tasks.append(CompilationTask('OverlayAppFirst/Android.mk')) tasks.append(CompilationTask('OverlayAppSecond/Android.mk')) + tasks.append(CompilationTask('OverlayAppFiltered/Android.mk')) # remount filesystem, install test project tasks.append(RootTask()) @@ -600,13 +642,13 @@ if __name__ == '__main__': tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1)) # idmap --scan - idmap = idmaps + '/vendor@overlay@framework_b.apk@idmap' tasks.append(StopTask()) tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks)) tasks.append(StartTask()) tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks)) - tasks.append(FileExistsTest(idmap)) - tasks.append(GrepIdmapTest(idmap, 'bool/config_annoy_dianne', 1)) + tasks.append(FileExistsTest(idmaps + '/vendor@overlay@framework_b.apk@idmap')) + tasks.append(GrepIdmapTest(idmaps + '/vendor@overlay@framework_b.apk@idmap', 'bool/config_annoy_dianne', 1)) + # overlays.list overlays_list_path = idmaps + '/overlays.list' @@ -620,27 +662,38 @@ if __name__ == '__main__': tasks.append(RmTask(symlinks)) tasks.append(RmTask(idmaps)) - # test no overlay + # test no overlay: all overlays cleared if opts.test_no_overlay: tasks.append(StopTask()) tasks.append(_create_disable_overlays_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest')) - # test single overlay + # test single overlay: one overlay (a) if opts.test_single_overlay: tasks.append(StopTask()) tasks.append(_create_enable_single_overlay_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest')) - # test multiple overlays + # test multiple overlays: all overlays - including 'disabled' filtered + # overlay (system property unset) so expect 'b[p=2]' overrides 'a[p=1]' but + # 'c[p=3]' should be ignored if opts.test_multiple_overlays: tasks.append(StopTask()) tasks.append(_create_enable_multiple_overlays_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest')) + # test filtered overlays: all overlays - including 'enabled' filtered + # overlay (system property set/matched) so expect c[p=3] to override both a + # & b where applicable + if opts.test_filtered_overlays: + tasks.append(StopTask()) + tasks.append(_create_enable_filtered_overlays_task()) + tasks.append(StartTask()) + tasks.append(InstrumentationTask('com.android.overlaytest.WithFilteredOverlaysTest')) + ignored_errors = 0 for t in tasks: type = t.get_type() diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp index ee202367d73e..773a7ea54a52 100644 --- a/libs/hwui/tests/unit/FontRendererTests.cpp +++ b/libs/hwui/tests/unit/FontRendererTests.cpp @@ -28,7 +28,7 @@ static bool isZero(uint8_t* data, int size) { return true; } -RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, DISABLED_renderDropShadow) { SkPaint paint; paint.setTextSize(10); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp index 8312bda8d67d..5383e5756b93 100644 --- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp +++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp @@ -26,7 +26,7 @@ using namespace android; using namespace android::uirenderer; -RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, DISABLED_addRemove) { SkPaint paint; paint.setTextSize(20); diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 5bf205e12799..789d5e0d8478 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -365,7 +365,7 @@ public final class MediaBrowser { * @param parentId The id of the parent media item whose list of children * will be subscribed. * @param options The bundle of service-specific arguments to send to the media - * browse service. The contents of this bundle may affect the + * browser service. The contents of this bundle may affect the * information returned when browsing. * @param callback The callback to receive the list of children. */ @@ -453,7 +453,7 @@ public final class MediaBrowser { try { mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks); } catch (RemoteException e) { - Log.i(TAG, "Remote error getting media item.", e); + Log.i(TAG, "Remote error getting media item."); mHandler.post(new Runnable() { @Override public void run() { @@ -463,62 +463,6 @@ public final class MediaBrowser { } } - /** - * Searches {@link MediaItem media items} from the connected service. Not - * all services may support this, and {@link SearchCallback#onError} will be - * called if not implemented. - * - * @param query The search query that contains keywords separated by space. Should not be - * an empty string. - * @param extras The bundle of service-specific arguments to send to the media browser - * service. The contents of this bundle may affect the search result. - * @param callback The callback to receive the search result. - * @throws IllegalStateException if the browser is not connected to the media browser service. - */ - public void search(@NonNull final String query, final Bundle extras, SearchCallback callback) { - if (TextUtils.isEmpty(query)) { - throw new IllegalArgumentException("query cannot be empty."); - } - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null."); - } - if (mState != CONNECT_STATE_CONNECTED) { - throw new IllegalStateException("search() called while not connected (state=" - + getStateLabel(mState) + ")"); - } - ResultReceiver receiver = new ResultReceiver(mHandler) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode != 0 || resultData == null - || !resultData.containsKey(MediaBrowserService.KEY_SEARCH_RESULTS)) { - callback.onError(query, extras); - return; - } - Parcelable[] items = resultData.getParcelableArray( - MediaBrowserService.KEY_SEARCH_RESULTS); - List<MediaItem> results = null; - if (items != null) { - results = new ArrayList<>(); - for (Parcelable item : items) { - results.add((MediaItem) item); - } - } - callback.onSearchResult(query, extras, results); - } - }; - try { - mServiceBinder.search(query, extras, receiver, mServiceCallbacks); - } catch (RemoteException e) { - Log.i(TAG, "Remote error getting media item.", e); - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onError(query, extras); - } - }); - } - } - private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) { // Check arguments. if (TextUtils.isEmpty(parentId)) { @@ -945,7 +889,7 @@ public final class MediaBrowser { * @param parentId The media id of the parent media item. * @param children The children which were loaded. * @param options The bundle of service-specific arguments sent to the media - * browse service. The contents of this bundle may affect the + * browser service. The contents of this bundle may affect the * information returned when browsing. */ public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children, @@ -1004,32 +948,6 @@ public final class MediaBrowser { } /** - * Callback for receiving the result of {@link #search}. - */ - public static abstract class SearchCallback { - /** - * Called when the {@link #search} finished successfully. - * - * @param query The search query sent for the search request to the connected service. - * @param extras The bundle of service-specific arguments sent to the connected service. - * @param items The list of media items which contains the search result. - */ - public void onSearchResult(@NonNull String query, Bundle extras, - @NonNull List<MediaItem> items) { - } - - /** - * Called when an error happens while {@link #search} or the connected service doesn't - * support {@link #search}. - * - * @param query The search query sent for the search request to the connected service. - * @param extras The bundle of service-specific arguments sent to the connected service. - */ - public void onError(@NonNull String query, Bundle extras) { - } - } - - /** * ServiceConnection to the other app. */ private class MediaServiceConnection implements ServiceConnection { diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl index a146c6226171..2f6e260741c4 100644 --- a/media/java/android/media/session/ISessionCallback.aidl +++ b/media/java/android/media/session/ISessionCallback.aidl @@ -16,7 +16,6 @@ package android.media.session; import android.content.Intent; -import android.media.MediaDescription; import android.media.Rating; import android.net.Uri; import android.os.Bundle; @@ -50,10 +49,6 @@ oneway interface ISessionCallback { void onRepeatMode(int repeatMode); void onShuffleMode(boolean enabled); void onCustomAction(String action, in Bundle args); - void onAddQueueItem(in MediaDescription description); - void onAddQueueItemAt(in MediaDescription description, int index); - void onRemoveQueueItem(in MediaDescription description); - void onRemoveQueueItemAt(int index); // These callbacks are for volume handling void onAdjustVolume(int direction); diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 7b5233ac0704..e92758c950af 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -18,7 +18,6 @@ package android.media.session; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ParceledListSlice; -import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; import android.media.session.ISessionControllerCallback; @@ -52,11 +51,6 @@ interface ISessionController { MediaMetadata getMetadata(); PlaybackState getPlaybackState(); ParceledListSlice getQueue(); - void addQueueItem(in MediaDescription description); - void addQueueItemAt(in MediaDescription description, int index); - void removeQueueItem(in MediaDescription description); - void removeQueueItemAt(int index); - CharSequence getQueueTitle(); Bundle getExtras(); int getRatingType(); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index bab2af25dde5..8cbf8e1eccdf 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; -import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; @@ -39,7 +38,6 @@ import android.util.Log; import android.view.KeyEvent; import java.lang.ref.WeakReference; -import java.lang.UnsupportedOperationException; import java.util.ArrayList; import java.util.List; @@ -113,7 +111,8 @@ public final class MediaController { } /** - * Get a {@link TransportControls} instance to send transport actions to this session. + * Get a {@link TransportControls} instance to send transport actions to + * the associated session. * * @return A transport controls instance. */ @@ -152,7 +151,7 @@ public final class MediaController { try { return mSessionBinder.getPlaybackState(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getPlaybackState", e); + Log.wtf(TAG, "Error calling getPlaybackState.", e); return null; } } @@ -166,7 +165,7 @@ public final class MediaController { try { return mSessionBinder.getMetadata(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getMetadata", e); + Log.wtf(TAG, "Error calling getMetadata.", e); return null; } } @@ -184,103 +183,12 @@ public final class MediaController { return queue.getList(); } } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getQueue", e); + Log.wtf(TAG, "Error calling getQueue.", e); } return null; } /** - * Add a queue item from the given {@code description} at the end of the play queue - * of this session. Not all sessions may support this. - * - * @param description The {@link MediaDescription} for creating the - * {@link MediaSession.QueueItem} to be inserted. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void addQueueItem(MediaDescription description) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.addQueueItem(description); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling addQueueItem", e); - } - } - - /** - * Add a queue item from the given {@code description} at the specified position - * in the play queue of this session. Shifts the queue item currently at that position - * (if any) and any subsequent queue items to the right (adds one to their indices). - * Not all sessions may support this. - * - * @param description The {@link MediaDescription} for creating the - * {@link MediaSession.QueueItem} to be inserted. - * @param index The index at which the created {@link MediaSession.QueueItem} is to be inserted. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void addQueueItem(MediaDescription description, int index) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.addQueueItemAt(description, index); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling addQueueItemAt", e); - } - } - - /** - * Remove the first occurrence of the specified {@link MediaSession.QueueItem} - * with the given {@link MediaDescription description} in the play queue of the associated - * session. Not all sessions may support this. - * - * @param description The {@link MediaDescription} for denoting the - * {@link MediaSession.QueueItem} to be removed. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void removeQueueItem(MediaDescription description) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.removeQueueItem(description); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling removeQueueItem", e); - } - } - - /** - * Remove an queue item at the specified position in the play queue - * of this session. Not all sessions may support this. - * - * @param index The index of the element to be removed. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void removeQueueItemAt(int index) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.removeQueueItemAt(index); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling removeQueueItemAt", e); - } - } - - /** * Get the queue title for this session. */ public @Nullable CharSequence getQueueTitle() { @@ -322,7 +230,7 @@ public final class MediaController { try { return mSessionBinder.getRatingType(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getRatingType", e); + Log.wtf(TAG, "Error calling getRatingType.", e); return Rating.RATING_NONE; } } @@ -337,7 +245,7 @@ public final class MediaController { try { return mSessionBinder.getRepeatMode(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getRepeatMode", e); + Log.wtf(TAG, "Error calling getRepeatMode.", e); return PlaybackState.REPEAT_MODE_NONE; } } @@ -351,7 +259,7 @@ public final class MediaController { try { return mSessionBinder.isShuffleModeEnabled(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling isShuffleModeEnabled", e); + Log.wtf(TAG, "Error calling isShuffleModeEnabled.", e); return false; } } @@ -365,7 +273,7 @@ public final class MediaController { try { return mSessionBinder.getFlags(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getFlags", e); + Log.wtf(TAG, "Error calling getFlags.", e); } return 0; } @@ -382,7 +290,7 @@ public final class MediaController { result.maxVolume, result.currentVolume); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getAudioInfo", e); + Log.wtf(TAG, "Error calling getAudioInfo.", e); } return null; } @@ -397,7 +305,7 @@ public final class MediaController { try { return mSessionBinder.getLaunchPendingIntent(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getPendingIntent", e); + Log.wtf(TAG, "Error calling getPendingIntent.", e); } return null; } @@ -426,7 +334,7 @@ public final class MediaController { try { mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName()); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling setVolumeTo", e); + Log.wtf(TAG, "Error calling setVolumeTo.", e); } } @@ -447,7 +355,7 @@ public final class MediaController { try { mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName()); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling adjustVolumeBy", e); + Log.wtf(TAG, "Error calling adjustVolumeBy.", e); } } @@ -513,7 +421,7 @@ public final class MediaController { try { mSessionBinder.sendCommand(command, args, cb); } catch (RemoteException e) { - Log.d(TAG, "Dead object in sendCommand", e); + Log.d(TAG, "Dead object in sendCommand.", e); } } @@ -527,7 +435,7 @@ public final class MediaController { try { mPackageName = mSessionBinder.getPackageName(); } catch (RemoteException e) { - Log.d(TAG, "Dead object in getPackageName", e); + Log.d(TAG, "Dead object in getPackageName.", e); } } return mPackageName; @@ -544,7 +452,7 @@ public final class MediaController { try { mTag = mSessionBinder.getTag(); } catch (RemoteException e) { - Log.d(TAG, "Dead object in getTag", e); + Log.d(TAG, "Dead object in getTag.", e); } } return mTag; @@ -744,7 +652,7 @@ public final class MediaController { try { mSessionBinder.prepare(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare", e); + Log.wtf(TAG, "Error calling prepare.", e); } } @@ -763,12 +671,12 @@ public final class MediaController { public void prepareFromMediaId(String mediaId, Bundle extras) { if (TextUtils.isEmpty(mediaId)) { throw new IllegalArgumentException( - "You must specify a non-empty String for prepareFromMediaId"); + "You must specify a non-empty String for prepareFromMediaId."); } try { mSessionBinder.prepareFromMediaId(mediaId, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + mediaId + ")", e); + Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e); } } @@ -794,7 +702,7 @@ public final class MediaController { try { mSessionBinder.prepareFromSearch(query, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + query + ")", e); + Log.wtf(TAG, "Error calling prepare(" + query + ").", e); } } @@ -813,12 +721,12 @@ public final class MediaController { public void prepareFromUri(Uri uri, Bundle extras) { if (uri == null || Uri.EMPTY.equals(uri)) { throw new IllegalArgumentException( - "You must specify a non-empty Uri for prepareFromUri"); + "You must specify a non-empty Uri for prepareFromUri."); } try { mSessionBinder.prepareFromUri(uri, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + uri + ")", e); + Log.wtf(TAG, "Error calling prepare(" + uri + ").", e); } } @@ -829,7 +737,7 @@ public final class MediaController { try { mSessionBinder.play(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play", e); + Log.wtf(TAG, "Error calling play.", e); } } @@ -843,12 +751,12 @@ public final class MediaController { public void playFromMediaId(String mediaId, Bundle extras) { if (TextUtils.isEmpty(mediaId)) { throw new IllegalArgumentException( - "You must specify a non-empty String for playFromMediaId"); + "You must specify a non-empty String for playFromMediaId."); } try { mSessionBinder.playFromMediaId(mediaId, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + mediaId + ")", e); + Log.wtf(TAG, "Error calling play(" + mediaId + ").", e); } } @@ -870,7 +778,7 @@ public final class MediaController { try { mSessionBinder.playFromSearch(query, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + query + ")", e); + Log.wtf(TAG, "Error calling play(" + query + ").", e); } } @@ -884,12 +792,12 @@ public final class MediaController { public void playFromUri(Uri uri, Bundle extras) { if (uri == null || Uri.EMPTY.equals(uri)) { throw new IllegalArgumentException( - "You must specify a non-empty Uri for playFromUri"); + "You must specify a non-empty Uri for playFromUri."); } try { mSessionBinder.playFromUri(uri, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + uri + ")", e); + Log.wtf(TAG, "Error calling play(" + uri + ").", e); } } @@ -901,7 +809,7 @@ public final class MediaController { try { mSessionBinder.skipToQueueItem(id); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling skipToItem(" + id + ")", e); + Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e); } } @@ -913,7 +821,7 @@ public final class MediaController { try { mSessionBinder.pause(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling pause", e); + Log.wtf(TAG, "Error calling pause.", e); } } @@ -925,7 +833,7 @@ public final class MediaController { try { mSessionBinder.stop(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling stop", e); + Log.wtf(TAG, "Error calling stop.", e); } } @@ -938,7 +846,7 @@ public final class MediaController { try { mSessionBinder.seekTo(pos); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling seekTo", e); + Log.wtf(TAG, "Error calling seekTo.", e); } } @@ -950,7 +858,7 @@ public final class MediaController { try { mSessionBinder.fastForward(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling fastForward", e); + Log.wtf(TAG, "Error calling fastForward.", e); } } @@ -961,7 +869,7 @@ public final class MediaController { try { mSessionBinder.next(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling next", e); + Log.wtf(TAG, "Error calling next.", e); } } @@ -973,7 +881,7 @@ public final class MediaController { try { mSessionBinder.rewind(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling rewind", e); + Log.wtf(TAG, "Error calling rewind.", e); } } @@ -984,7 +892,7 @@ public final class MediaController { try { mSessionBinder.previous(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling previous", e); + Log.wtf(TAG, "Error calling previous.", e); } } @@ -999,7 +907,7 @@ public final class MediaController { try { mSessionBinder.rate(rating); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling rate", e); + Log.wtf(TAG, "Error calling rate.", e); } } @@ -1015,7 +923,7 @@ public final class MediaController { try { mSessionBinder.repeatMode(repeatMode); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling setRepeatMode", e); + Log.wtf(TAG, "Error calling setRepeatMode.", e); } } @@ -1028,7 +936,7 @@ public final class MediaController { try { mSessionBinder.shuffleMode(enabled); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling shuffleMode", e); + Log.wtf(TAG, "Error calling shuffleMode.", e); } } @@ -1042,7 +950,7 @@ public final class MediaController { public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, @Nullable Bundle args) { if (customAction == null) { - throw new IllegalArgumentException("CustomAction cannot be null"); + throw new IllegalArgumentException("CustomAction cannot be null."); } sendCustomAction(customAction.getAction(), args); } @@ -1058,12 +966,12 @@ public final class MediaController { */ public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { if (TextUtils.isEmpty(action)) { - throw new IllegalArgumentException("CustomAction cannot be null"); + throw new IllegalArgumentException("CustomAction cannot be null."); } try { mSessionBinder.sendCustomAction(action, args); } catch (RemoteException e) { - Log.d(TAG, "Dead object in sendCustomAction", e); + Log.d(TAG, "Dead object in sendCustomAction.", e); } } } diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index f10f4427d6f0..6688840d25ae 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -93,12 +93,6 @@ public final class MediaSession { public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1; /** - * Set this flag on the session to indicate that it handles queue - * management commands through its {@link Callback}. - */ - public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2; - - /** * System only flag for a session that needs to have priority over all other * sessions. This flag ensures this session will receive media button events * regardless of the current ordering in the system. @@ -112,7 +106,6 @@ public final class MediaSession { @IntDef(flag = true, value = { FLAG_HANDLES_MEDIA_BUTTONS, FLAG_HANDLES_TRANSPORT_CONTROLS, - FLAG_HANDLES_QUEUE_COMMANDS, FLAG_EXCLUSIVE_GLOBAL_PRIORITY }) public @interface SessionFlags { } @@ -658,22 +651,6 @@ public final class MediaSession { postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args); } - private void dispatchAddQueueItem(MediaDescription description) { - postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM, description); - } - - private void dispatchAddQueueItem(MediaDescription description, int index) { - postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM_AT, description, index); - } - - private void dispatchRemoveQueueItem(MediaDescription description) { - postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM, description); - } - - private void dispatchRemoveQueueItemAt(int index) { - postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM_AT, index); - } - private void dispatchMediaButton(Intent mediaButtonIntent) { postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent); } @@ -695,22 +672,10 @@ public final class MediaSession { postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd); } - private void postToCallback(int what, int arg1) { - postToCallback(what, null, arg1); - } - private void postToCallback(int what, Object obj) { postToCallback(what, obj, null); } - private void postToCallback(int what, Object obj, int arg1) { - synchronized (mLock) { - if (mCallback != null) { - mCallback.post(what, obj, arg1); - } - } - } - private void postToCallback(int what, Object obj, Bundle extras) { synchronized (mLock) { if (mCallback != null) { @@ -1084,47 +1049,6 @@ public final class MediaSession { */ public void onCustomAction(@NonNull String action, @Nullable Bundle extras) { } - - /** - * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given - * {@link MediaDescription description} at the end of the play queue. - * - * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be - * inserted. - */ - public void onAddQueueItem(MediaDescription description) { - } - - /** - * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given - * {@link MediaDescription description} at the specified position in the play queue. - * - * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be - * inserted. - * @param index The index at which the created {@link QueueItem} is to be inserted. - */ - public void onAddQueueItem(MediaDescription description, int index) { - } - - /** - * Called when a {@link MediaController} wants to remove the first occurrence of the - * specified {@link QueueItem} with the given {@link MediaDescription description} - * in the play queue. - * - * @param description The {@link MediaDescription} for denoting the {@link QueueItem} to be - * removed. - */ - public void onRemoveQueueItem(MediaDescription description) { - } - - /** - * Called when a {@link MediaController} wants to remove a {@link QueueItem} at the - * specified position in the play queue. - * - * @param index The index of the element to be removed. - */ - public void onRemoveQueueItemAt(int index) { - } } /** @@ -1321,38 +1245,6 @@ public final class MediaSession { } @Override - public void onAddQueueItem(MediaDescription description) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchAddQueueItem(description); - } - } - - @Override - public void onAddQueueItemAt(MediaDescription description, int index) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchAddQueueItem(description, index); - } - } - - @Override - public void onRemoveQueueItem(MediaDescription description) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchRemoveQueueItem(description); - } - } - - @Override - public void onRemoveQueueItemAt(int index) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchRemoveQueueItemAt(index); - } - } - - @Override public void onAdjustVolume(int direction) { MediaSession session = mMediaSession.get(); if (session != null) { @@ -1490,10 +1382,6 @@ public final class MediaSession { private static final int MSG_CUSTOM_ACTION = 22; private static final int MSG_ADJUST_VOLUME = 23; private static final int MSG_SET_VOLUME = 24; - private static final int MSG_ADD_QUEUE_ITEM = 25; - private static final int MSG_ADD_QUEUE_ITEM_AT = 26; - private static final int MSG_REMOVE_QUEUE_ITEM = 27; - private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28; private MediaSession.Callback mCallback; @@ -1583,7 +1471,7 @@ public final class MediaSession { mCallback.onSetRating((Rating) msg.obj); break; case MSG_REPEAT_MODE: - mCallback.onSetRepeatMode(msg.arg1); + mCallback.onSetRepeatMode((int) msg.obj); break; case MSG_SHUFFLE_MODE: mCallback.onSetShuffleModeEnabled((boolean) msg.obj); @@ -1591,24 +1479,12 @@ public final class MediaSession { case MSG_CUSTOM_ACTION: mCallback.onCustomAction((String) msg.obj, msg.getData()); break; - case MSG_ADD_QUEUE_ITEM: - mCallback.onAddQueueItem((MediaDescription) msg.obj); - break; - case MSG_ADD_QUEUE_ITEM_AT: - mCallback.onAddQueueItem((MediaDescription) msg.obj, msg.arg1); - break; - case MSG_REMOVE_QUEUE_ITEM: - mCallback.onRemoveQueueItem((MediaDescription) msg.obj); - break; - case MSG_REMOVE_QUEUE_ITEM_AT: - mCallback.onRemoveQueueItemAt(msg.arg1); - break; case MSG_ADJUST_VOLUME: synchronized (mLock) { vp = mVolumeProvider; } if (vp != null) { - vp.onAdjustVolume(msg.arg1); + vp.onAdjustVolume((int) msg.obj); } break; case MSG_SET_VOLUME: @@ -1616,7 +1492,7 @@ public final class MediaSession { vp = mVolumeProvider; } if (vp != null) { - vp.onSetVolumeTo(msg.arg1); + vp.onSetVolumeTo((int) msg.obj); } break; } diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 1b55380ed5a9..71f9ba257aa3 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -436,6 +436,14 @@ public final class TvContract { public static final String PARAM_CANONICAL_GENRE = "canonical_genre"; /** + * A query, update or delete URI parameter that allows the caller to operate only on preview or + * non-preview channels. If set to "true", the operation affects the rows for preview channels + * only. If set to "false", the operation affects the rows for non-preview channels only. + * @hide + */ + public static final String PARAM_PREVIEW = "preview"; + + /** * Builds an ID that uniquely identifies a TV input service. * * @param name The {@link ComponentName} of the TV input service to build ID for. diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl index e95154ff4540..84f41f6c3afe 100644 --- a/media/java/android/service/media/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl @@ -19,10 +19,8 @@ oneway interface IMediaBrowserService { void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks); void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks); - void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks); - void search(String query, in Bundle extras, in ResultReceiver cb, - IMediaBrowserServiceCallbacks callbacks); + void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks); void addSubscription(String uri, in IBinder token, in Bundle options, IMediaBrowserServiceCallbacks callbacks); void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks); diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index d372efbea5ca..b52906ddd1ae 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -89,15 +89,8 @@ public abstract class MediaBrowserService extends Service { */ public static final String KEY_MEDIA_ITEM = "media_item"; - /** - * A key for passing the list of MediaItems to the ResultReceiver in search. - * @hide - */ - public static final String KEY_SEARCH_RESULTS = "search_results"; - private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0; private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1; - private static final int RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED = 1 << 2; private static final int RESULT_ERROR = -1; private static final int RESULT_OK = 0; @@ -105,7 +98,7 @@ public abstract class MediaBrowserService extends Service { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED, - RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED, RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED }) + RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED }) private @interface ResultFlags { } private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>(); @@ -137,7 +130,6 @@ public abstract class MediaBrowserService extends Service { * * @see #onLoadChildren * @see #onLoadItem - * @see #onSearch */ public class Result<T> { private Object mDebug; @@ -330,23 +322,6 @@ public abstract class MediaBrowserService extends Service { } }); } - - @Override - public void search(final String query, Bundle extras, ResultReceiver receiver, - final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { - @Override - public void run() { - final IBinder b = callbacks.asBinder(); - ConnectionRecord connection = mConnections.get(b); - if (connection == null) { - Log.w(TAG, "search for callback that isn't registered query=" + query); - return; - } - performSearch(query, extras, connection, receiver); - } - }); - } } @Override @@ -472,32 +447,6 @@ public abstract class MediaBrowserService extends Service { } /** - * Called to get the search result. - * <p> - * Implementations must call {@link Result#sendResult result.sendResult}. If - * the search will be an expensive operation {@link Result#detach result.detach} - * may be called before returning from this function, and then {@link Result#sendResult - * result.sendResult} called when the search has been completed. - * </p><p> - * In case there are no search results, call {@link Result#sendResult} with an empty list. - * In case there are some errors happened, call {@link Result#sendResult result.sendResult} - * with {@code null}, which will invoke {@link MediaBrowser.SearchCallback#onError}. - * </p><p> - * The default implementation will invoke {@link MediaBrowser.SearchCallback#onError}. - * </p> - * - * @param query The search query sent from the media browser. It contains keywords separated - * by space. - * @param extras The bundle of service-specific arguments sent from the media browser. - * @param result The {@link Result} to send the search result. - */ - public void onSearch(@NonNull String query, Bundle extras, - Result<List<MediaBrowser.MediaItem>> result) { - result.setFlags(RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED); - result.sendResult(null); - } - - /** * Call to set the media session. * <p> * This should be called as soon as possible during the service's startup. @@ -545,16 +494,16 @@ public abstract class MediaBrowserService extends Service { * media browser service when connecting and retrieving the root id for browsing, or null if * none. The contents of this bundle may affect the information returned when browsing. * - * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren}, - * {@link #onLoadItem} or {@link #onSearch}. + * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren} or + * {@link #onLoadItem}. * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED */ public final Bundle getBrowserRootHints() { if (mCurConnection == null) { - throw new IllegalStateException("This should be called inside of onLoadChildren," - + " onLoadItem or onSearch methods"); + throw new IllegalStateException("This should be called inside of onLoadChildren or" + + " onLoadItem methods"); } return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); } @@ -771,34 +720,6 @@ public abstract class MediaBrowserService extends Service { } } - private void performSearch(String query, Bundle extras, final ConnectionRecord connection, - final ResultReceiver receiver) { - final Result<List<MediaBrowser.MediaItem>> result = - new Result<List<MediaBrowser.MediaItem>>(query) { - @Override - void onResultSent(List<MediaBrowser.MediaItem> items, @ResultFlags int flag) { - if ((flag & RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED) != 0 - || items == null) { - receiver.send(RESULT_ERROR, null); - return; - } - Bundle bundle = new Bundle(); - bundle.putParcelableArray(KEY_SEARCH_RESULTS, - items.toArray(new MediaBrowser.MediaItem[0])); - receiver.send(RESULT_OK, bundle); - } - }; - - mCurConnection = connection; - onSearch(query, extras, result); - mCurConnection = null; - - if (!result.isDone()) { - throw new IllegalStateException("onSearch must call detach() or sendResult()" - + " before returning for query=" + query); - } - } - /** * Contains information that the browser service needs to send to the client * when first connected. diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp index ae16949791bc..8e5821024cee 100644 --- a/native/android/sensor.cpp +++ b/native/android/sensor.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "sensor" #include <utils/Log.h> -#include <android/hardware_buffer.h> #include <android/looper.h> #include <android/sensor.h> #include <android/sharedmem.h> @@ -28,6 +27,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/Timers.h> +#include <vndk/hardware_buffer.h> #include <poll.h> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 8a86c13abb7d..10f3b6341e42 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -29,6 +29,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageStats; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; @@ -52,6 +53,7 @@ import com.android.internal.util.ArrayUtils; import com.android.settingslib.R; import java.io.File; +import java.io.IOException; import java.text.Collator; import java.text.Normalizer; import java.text.Normalizer.Form; @@ -61,6 +63,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.regex.Pattern; /** @@ -114,7 +117,7 @@ public class ApplicationsState { final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>(); List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>(); long mCurId = 1; - String mCurComputingSizeUuid; + UUID mCurComputingSizeUuid; String mCurComputingSizePkg; int mCurComputingSizeUserId; boolean mSessionsChanged; @@ -334,15 +337,23 @@ public class ApplicationsState { AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry != null && (entry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { mBackgroundHandler.post(() -> { - final StorageStats stats = mStats.queryStatsForPackage(entry.info.volumeUuid, - packageName, UserHandle.of(userId)); - final PackageStats legacyStats = new PackageStats(packageName, userId); - legacyStats.codeSize = stats.getCodeBytes(); - legacyStats.dataSize = stats.getDataBytes(); - legacyStats.cacheSize = stats.getCacheBytes(); try { - mBackgroundHandler.mStatsObserver.onGetStatsCompleted(legacyStats, true); - } catch (RemoteException ignored) { + final StorageStats stats = mStats.queryStatsForPackage( + entry.info.storageUuid, packageName, UserHandle.of(userId)); + final PackageStats legacy = new PackageStats(packageName, userId); + legacy.codeSize = stats.getCodeBytes(); + legacy.dataSize = stats.getDataBytes(); + legacy.cacheSize = stats.getCacheBytes(); + try { + mBackgroundHandler.mStatsObserver.onGetStatsCompleted(legacy, true); + } catch (RemoteException ignored) { + } + } catch (NameNotFoundException | IOException e) { + Log.w(TAG, "Failed to query stats: " + e); + try { + mBackgroundHandler.mStatsObserver.onGetStatsCompleted(null, false); + } catch (RemoteException ignored) { + } } }); } @@ -979,7 +990,7 @@ public class ApplicationsState { mMainHandler.sendMessage(m); } entry.sizeLoadStart = now; - mCurComputingSizeUuid = entry.info.volumeUuid; + mCurComputingSizeUuid = entry.info.storageUuid; mCurComputingSizePkg = entry.info.packageName; mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); @@ -988,17 +999,17 @@ public class ApplicationsState { final StorageStats stats = mStats.queryStatsForPackage( mCurComputingSizeUuid, mCurComputingSizePkg, UserHandle.of(mCurComputingSizeUserId)); - final PackageStats legacyStats = new PackageStats( + final PackageStats legacy = new PackageStats( mCurComputingSizePkg, mCurComputingSizeUserId); - legacyStats.codeSize = stats.getCodeBytes(); - legacyStats.dataSize = stats.getDataBytes(); - legacyStats.cacheSize = stats.getCacheBytes(); + legacy.codeSize = stats.getCodeBytes(); + legacy.dataSize = stats.getDataBytes(); + legacy.cacheSize = stats.getCacheBytes(); try { - mStatsObserver.onGetStatsCompleted(legacyStats, true); + mStatsObserver.onGetStatsCompleted(legacy, true); } catch (RemoteException ignored) { } - } catch (IllegalStateException e) { - Log.e(TAG,"An exception occurred while fetching app size", e); + } catch (NameNotFoundException | IOException e) { + Log.w(TAG, "Failed to query stats: " + e); try { mStatsObserver.onGetStatsCompleted(null, false); } catch (RemoteException ignored) { diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java index 21835738fd69..34fdc9ddd99d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java @@ -19,9 +19,12 @@ package com.android.settingslib.applications; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.os.UserHandle; import android.support.annotation.VisibleForTesting; +import java.io.IOException; + /** * StorageStatsSource wraps the StorageStatsManager for testability purposes. */ @@ -32,17 +35,21 @@ public class StorageStatsSource { mStorageStatsManager = context.getSystemService(StorageStatsManager.class); } - public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, UserHandle user) { + public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, + UserHandle user) throws IOException { return new StorageStatsSource.ExternalStorageStats( mStorageStatsManager.queryExternalStatsForUser(volumeUuid, user)); } - public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) { - return new StorageStatsSource.AppStorageStatsImpl(mStorageStatsManager.queryStatsForUid(volumeUuid, uid)); + public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) + throws IOException { + return new StorageStatsSource.AppStorageStatsImpl( + mStorageStatsManager.queryStatsForUid(volumeUuid, uid)); } public StorageStatsSource.AppStorageStats getStatsForPackage( - String volumeUuid, String packageName, UserHandle user) { + String volumeUuid, String packageName, UserHandle user) + throws PackageManager.NameNotFoundException, IOException { return new StorageStatsSource.AppStorageStatsImpl( mStorageStatsManager.queryStatsForPackage(volumeUuid, packageName, user)); } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java index 88f133ce57c2..ccf7a0bfdfc6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java @@ -20,11 +20,16 @@ import android.app.AppGlobals; import android.app.usage.StorageStatsManager; import android.content.Context; import android.os.storage.VolumeInfo; +import android.util.Log; + +import java.io.IOException; /** * PrivateStorageInfo provides information about the total and free storage on the device. */ public class PrivateStorageInfo { + private static final String TAG = "PrivateStorageInfo"; + public final long freeBytes; public final long totalBytes; @@ -41,8 +46,12 @@ public class PrivateStorageInfo { long privateTotalBytes = 0; for (VolumeInfo info : sm.getVolumes()) { if (info.getType() == VolumeInfo.TYPE_PRIVATE && info.isMountedReadable()) { - privateTotalBytes += sm.getTotalBytes(stats, info); - privateFreeBytes += sm.getFreeBytes(stats, info); + try { + privateTotalBytes += sm.getTotalBytes(stats, info); + privateFreeBytes += sm.getFreeBytes(stats, info); + } catch (IOException e) { + Log.w(TAG, e); + } } } return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes); @@ -51,6 +60,11 @@ public class PrivateStorageInfo { public static long getTotalSize(VolumeInfo info, long totalInternalStorage) { final Context context = AppGlobals.getInitialApplication(); final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); - return stats.getTotalBytes(info.getFsUuid()); + try { + return stats.getTotalBytes(info.getFsUuid()); + } catch (IOException e) { + Log.w(TAG, e); + return 0; + } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java index 11060e6c1a05..b57b6cc544fa 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java @@ -20,6 +20,7 @@ import android.app.usage.StorageStatsManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import java.io.IOException; import java.util.List; /** @@ -49,12 +50,12 @@ public class StorageManagerVolumeProvider implements StorageVolumeProvider { } @Override - public long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) { + public long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException { return stats.getTotalBytes(volume.getFsUuid()); } @Override - public long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) { + public long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException { return stats.getFreeBytes(volume.getFsUuid()); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index 60e10a125d0b..ea28fe68e91b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -32,6 +32,7 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.List; @@ -154,7 +155,7 @@ public class StorageMeasurement { try { details.totalSize = mStats.getTotalBytes(mVolume.fsUuid); details.availSize = mStats.getFreeBytes(mVolume.fsUuid); - } catch (IllegalStateException e) { + } catch (IOException e) { // The storage volume became null while we were measuring it. Log.w(TAG, e); return details; @@ -169,8 +170,14 @@ public class StorageMeasurement { final HashMap<String, Long> mediaMap = new HashMap<>(); details.mediaSize.put(user.id, mediaMap); - final ExternalStorageStats stats = mStats - .queryExternalStatsForUser(mSharedVolume.fsUuid, UserHandle.of(user.id)); + final ExternalStorageStats stats; + try { + stats = mStats.queryExternalStatsForUser(mSharedVolume.fsUuid, + UserHandle.of(user.id)); + } catch (IOException e) { + Log.w(TAG, e); + continue; + } addValue(details.usersSize, user.id, stats.getTotalBytes()); @@ -190,8 +197,13 @@ public class StorageMeasurement { if ((mVolume.getType() == VolumeInfo.TYPE_PRIVATE) && mVolume.isMountedReadable()) { for (UserInfo user : users) { - final StorageStats stats = mStats.queryStatsForUser(mVolume.fsUuid, - UserHandle.of(user.id)); + final StorageStats stats; + try { + stats = mStats.queryStatsForUser(mVolume.fsUuid, UserHandle.of(user.id)); + } catch (IOException e) { + Log.w(TAG, e); + continue; + } // Only count code once against current user if (user.id == UserHandle.myUserId()) { diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java index e5d85d147bee..4c4541315e07 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java @@ -19,6 +19,7 @@ package com.android.settingslib.deviceinfo; import android.app.usage.StorageStatsManager; import android.os.storage.VolumeInfo; +import java.io.IOException; import java.util.List; /** @@ -46,12 +47,12 @@ public interface StorageVolumeProvider { * * @pre The volume is a private volume and is readable. */ - long getTotalBytes(StorageStatsManager stats, VolumeInfo volume); + long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException; /** * Returns the free bytes for a given storage volume. * * @pre The volume is a private volume and is readable. */ - long getFreeBytes(StorageStatsManager stats, VolumeInfo volume); + long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException; } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java index d6bde8132327..9d09737a14dc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java @@ -40,6 +40,8 @@ public final class CategoryKey { "com.android.settings.category.ia.language"; public static final String CATEGORY_SYSTEM_DEVELOPMENT = "com.android.settings.category.ia.development"; + public static final String CATEGORY_NOTIFICATIONS = + "com.android.settings.category.ia.notifications"; public static final Map<String, String> KEY_COMPAT_MAP; diff --git a/packages/SystemUI/res/color/segmented_button_text_selector.xml b/packages/SystemUI/res/color/segmented_button_text_selector.xml index 537cbb84f647..d4f01816a608 100644 --- a/packages/SystemUI/res/color/segmented_button_text_selector.xml +++ b/packages/SystemUI/res/color/segmented_button_text_selector.xml @@ -18,4 +18,4 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="?android:attr/textColorPrimary"/> <item android:alpha="0.58" android:color="?android:attr/colorForeground"/> -</selector>
\ No newline at end of file +</selector> diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml index 17ecf217b86b..e658e687821b 100644 --- a/packages/SystemUI/res/drawable/ic_dnd.xml +++ b/packages/SystemUI/res/drawable/ic_dnd.xml @@ -17,7 +17,8 @@ android:height="24dp" android:viewportHeight="48.0" android:viewportWidth="48.0" - android:width="24dp" > + android:width="24dp" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml b/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml index 487597454e27..0515b35fb875 100644 --- a/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml +++ b/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml @@ -17,7 +17,8 @@ android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" - android:width="24dp" > + android:width="24dp" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml b/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml index 5aecebae1865..169cc71722a2 100644 --- a/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml +++ b/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml @@ -16,7 +16,6 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="root" - android:alpha="0.3" android:height="48dp" android:width="48dp" android:viewportHeight="48" diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml index 236fdac09c4b..5e7cd974818a 100644 --- a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml +++ b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml @@ -17,7 +17,8 @@ Copyright (C) 2014 The Android Open Source Project android:width="6.0dp" android:height="32dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/textColorSecondary"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.000000,15.700000l-3.000000,5.599999 -3.000000,-5.599999z"/> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml index c510972a5df8..0dca1db32f88 100644 --- a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml +++ b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml @@ -17,7 +17,8 @@ Copyright (C) 2014 The Android Open Source Project android:width="6.0dp" android:height="32dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/textColorSecondary"> <path android:fillColor="#FFFFFFFF" android:pathData="M0.000000,13.700000l3.000000,-5.700000 3.000000,5.700000z"/> diff --git a/packages/SystemUI/res/drawable/segmented_buttons_background.xml b/packages/SystemUI/res/drawable/segmented_buttons_background.xml index b243dc7ce8c0..755c917cf20c 100644 --- a/packages/SystemUI/res/drawable/segmented_buttons_background.xml +++ b/packages/SystemUI/res/drawable/segmented_buttons_background.xml @@ -17,6 +17,6 @@ <corners android:radius="@dimen/borderless_button_radius" /> - <solid android:color="@color/segmented_buttons_background" /> + <solid android:color="?android:attr/colorPrimaryDark" /> -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml index d7463a446657..be9a7e266c6f 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" - android:height="17dp" - android:viewportWidth="12.0" - android:viewportHeight="24.0"> + android:width="17dp" + android:height="17dp" + android:viewportWidth="12.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml index 6309b6d9903b..fd7a65841129 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="9.208dp" + android:width="17dp" android:height="17dp" android:viewportWidth="13.0" - android:viewportHeight="24.0"> + android:viewportHeight="13.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml index 4067ae5b4800..02c4ab6161c6 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" + android:width="17dp" android:height="17dp" android:viewportWidth="12.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml index 3cdd3e104bfb..daf40618c24a 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml @@ -14,10 +14,10 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17.0dp" + android:width="25.5dp" android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportWidth="18.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml index acaa9b1c2be8..cd0cc6585391 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="3.541dp" + android:width="7.083dp" android:height="17dp" android:viewportWidth="5.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml index 7985237d8a44..92ed49c71189 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="4.958dp" + android:width="9.154dp" android:height="17dp" android:viewportWidth="7.0" - android:viewportHeight="24.0"> + android:viewportHeight="13"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml index fda87612582e..ca61b6f0299c 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="4.25dp" + android:width="9.5dp" android:height="17dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml index c08ff20c54fc..add96b4352e8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="9.208dp" + android:width="18.417dp" android:height="17dp" - android:viewportWidth="13.0" - android:viewportHeight="24.0"> + android:viewportWidth="13" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml index db18fad637e7..8811d2f9b7ba 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml @@ -14,10 +14,10 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17.0dp" + android:width="25.0dp" android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportWidth="18.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml index 4baa472acb88..363e231cf03c 100644 --- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml +++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" + android:width="4.25dp" android:height="17dp" android:viewportWidth="6.0" - android:viewportHeight="12.0"> + android:viewportHeight="24.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml new file mode 100644 index 000000000000..f4e8af468b76 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml @@ -0,0 +1,42 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18.41dp" + android:height="17dp" + android:viewportWidth="26.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M21.0,8.5 + c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79 + C25.1,5.96 20.26,2.0 13.0,2.0 + S0.9,5.9 0.42,6.32 + l12.57,15.6 4.21,-5.17 + c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25 + c0.0,-2.76 2.24,-5.0 5.0,-5.0z" + android:fillAlpha=".3"/> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M21.0,10.0 + c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0 + c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75 + c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1 + c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0 + c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8 + c0.5,-0.5 0.82,-1.2 0.82,-1.97 + C24.5,11.57 22.93,10.0 21.0,10.0z + m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml index 5169de46ea29..c1856fa30e7e 100644 --- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml +++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml @@ -20,5 +20,8 @@ Copyright (C) 2014 The Android Open Source Project android:viewportHeight="24.0"> <path android:fillColor="?attr/backgroundColor" - android:pathData="M13.000000,2.000000C7.700000,2.000000 3.700000,3.900000 0.400000,6.400000L13.000000,22.000000L25.600000,6.500000C22.299999,4.000000 18.299999,2.000000 13.000000,2.000000zM13.000000,18.600000L3.300000,7.000000l0.000000,0.000000l0.000000,0.000000C6.000000,5.300000 8.700000,4.000000 13.000000,4.000000s7.000000,1.400000 9.700000,3.000000l0.000000,0.000000l0.000000,0.000000L13.000000,18.600000z"/> + android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"/> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"/> </vector> diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml index 33effba53059..6d4365c644e4 100644 --- a/packages/SystemUI/res/layout/mobile_signal_group.xml +++ b/packages/SystemUI/res/layout/mobile_signal_group.xml @@ -63,20 +63,21 @@ systemui:hasOverlappingRendering="false" /> <ImageView - android:id="@+id/mobile_type" + android:id="@+id/mobile_roaming" android:layout_height="wrap_content" android:layout_width="wrap_content" + android:src="@drawable/stat_sys_roaming" + android:contentDescription="@string/accessibility_data_connection_roaming" + android:visibility="gone" /> <ImageView - android:id="@+id/mobile_roaming" + android:id="@+id/mobile_type" android:layout_width="wrap_content" android:layout_height="17dp" - android:paddingStart="22dp" + android:paddingStart="19dp" android:paddingTop="1.5dp" android:paddingBottom="3dp" android:scaleType="fitCenter" - android:src="@drawable/stat_sys_roaming" - android:contentDescription="@string/accessibility_data_connection_roaming" android:visibility="gone" /> </FrameLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index ff22ffb319fb..0c9858dc8397 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -114,6 +114,7 @@ android:layout_height="wrap_content" android:layout_gravity="end|center_vertical" android:layout_weight="1" + android:contentDescription="@string/notification_channel_switch_accessibility" android:background="@null" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml index da7e4d79fc46..5766dc1c5b4f 100644 --- a/packages/SystemUI/res/layout/signal_cluster_view.xml +++ b/packages/SystemUI/res/layout/signal_cluster_view.xml @@ -52,9 +52,54 @@ android:alpha="0.0" /> </FrameLayout> + <ViewStub + android:id="@+id/connected_device_signals_stub" + android:layout="@layout/connected_device_signal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + <LinearLayout + android:id="@+id/mobile_signal_group" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + > + </LinearLayout> + <View + android:id="@+id/wifi_signal_spacer" + android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" + android:layout_height="4dp" + android:visibility="gone" + /> + <FrameLayout + android:id="@+id/no_sims_combo" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:contentDescription="@string/accessibility_no_sims"> + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:theme="@style/DualToneLightTheme" + android:id="@+id/no_sims" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/stat_sys_no_sims" + /> + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:theme="@style/DualToneDarkTheme" + android:id="@+id/no_sims_dark" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/stat_sys_no_sims" + android:alpha="0.0" + /> + </FrameLayout> + <View + android:id="@+id/wifi_airplane_spacer" + android:layout_width="@dimen/status_bar_airplane_spacer_width" + android:layout_height="4dp" + android:visibility="gone" + /> <FrameLayout android:layout_height="17dp" - android:layout_width="wrap_content"> + android:layout_width="wrap_content" + android:paddingStart="2dp"> <ImageView android:id="@+id/wifi_in" android:layout_height="wrap_content" @@ -96,50 +141,6 @@ android:layout_width="wrap_content" /> </FrameLayout> - <View - android:id="@+id/wifi_signal_spacer" - android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" - android:layout_height="4dp" - android:visibility="gone" - /> - <ViewStub - android:id="@+id/connected_device_signals_stub" - android:layout="@layout/connected_device_signal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - <LinearLayout - android:id="@+id/mobile_signal_group" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - > - </LinearLayout> - <FrameLayout - android:id="@+id/no_sims_combo" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:contentDescription="@string/accessibility_no_sims"> - <com.android.systemui.statusbar.AlphaOptimizedImageView - android:theme="@style/DualToneLightTheme" - android:id="@+id/no_sims" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/stat_sys_no_sims" - /> - <com.android.systemui.statusbar.AlphaOptimizedImageView - android:theme="@style/DualToneDarkTheme" - android:id="@+id/no_sims_dark" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/stat_sys_no_sims" - android:alpha="0.0" - /> - </FrameLayout> - <View - android:id="@+id/wifi_airplane_spacer" - android:layout_width="@dimen/status_bar_airplane_spacer_width" - android:layout_height="4dp" - android:visibility="gone" - /> <ImageView android:id="@+id/airplane" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index eeb28c825ffa..33b1dd40e471 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1466,6 +1466,15 @@ <item quantity="other"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> others</item> </plurals> + <!-- Notification: Control panel: Accessibility description for expanded inline controls view, used + to control settings about notifications related to the current notification. --> + <string name="notification_channel_controls_opened_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> opened</string> + <!-- Notification: Control panel: Accessibility description for announcing the closing of the + inline controls view. --> + <string name="notification_channel_controls_closed_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> closed</string> + <!-- Notification: Control panel: Accessibility description for switch that is used to enable + or disable notifications from this channel --> + <string name="notification_channel_switch_accessibility">Allow notifications from this channel</string> <!-- Notification: Control panel: Label for button that launches notification settings. Used when this app has defined more than a single channel for notifications. --> <string name="notification_all_categories">All Categories</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index c9479b8b41f7..e5f04c6186b8 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -299,13 +299,13 @@ <style name="TextAppearance.Volume"> <item name="android:textStyle">normal</item> - <item name="android:textColor">#ffffffff</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:fontFamily">sans-serif</item> </style> <style name="TextAppearance.Volume.Header"> <item name="android:textSize">12sp</item> - <item name="android:textColor">@color/volume_slider_inactive</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.Volume.ZenSummary"> @@ -316,7 +316,7 @@ <style name="TextAppearance.Volume.ZenDetail"> <item name="android:textSize">14sp</item> <item name="android:fontFamily">sans-serif</item> - <item name="android:textColor">@*android:color/quaternary_device_default_settings</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless"> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index b447979be45d..616e5b9830ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -15,6 +15,7 @@ */ package com.android.keyguard; +import android.R.style; import android.app.Activity; import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; @@ -23,6 +24,7 @@ import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; @@ -73,7 +75,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); + super(new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault), attrs, + defStyle); mSecurityModel = new KeyguardSecurityModel(context); mLockPatternUtils = new LockPatternUtils(context); mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 870d4d1c6a9d..90e1c0723945 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -145,6 +145,11 @@ public class DozeLog { log("screenOff why=" + why); } + public static void traceMissedTick(String delay) { + if (!ENABLED) return; + log("missedTick by=" + delay); + } + public static void traceKeyguard(boolean showing) { if (!ENABLED) return; log("keyguard " + showing); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 6098a20a0c64..03076cc4b7a8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -20,6 +20,8 @@ import android.app.AlarmManager; import android.content.Context; import android.os.Handler; import android.os.SystemClock; +import android.text.format.Formatter; +import android.util.Log; import com.android.systemui.util.wakelock.WakeLock; @@ -31,6 +33,7 @@ import java.util.GregorianCalendar; */ public class DozeUi implements DozeMachine.Part { + private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min private final Context mContext; private final AlarmManager mAlarmManager; private final DozeHost mHost; @@ -40,6 +43,7 @@ public class DozeUi implements DozeMachine.Part { private final AlarmManager.OnAlarmListener mTimeTick; private boolean mTimeTickScheduled = false; + private long mLastTimeTickElapsed = 0; public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine, WakeLock wakeLock, DozeHost host, Handler handler) { @@ -103,15 +107,26 @@ public class DozeUi implements DozeMachine.Part { SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler); mTimeTickScheduled = true; + mLastTimeTickElapsed = SystemClock.elapsedRealtime(); } private void unscheduleTimeTick() { if (!mTimeTickScheduled) { return; } + verifyLastTimeTick(); mAlarmManager.cancel(mTimeTick); } + private void verifyLastTimeTick() { + long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed; + if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) { + String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick); + DozeLog.traceMissedTick(delay); + Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay); + } + } + private long roundToNextMinute(long timeInMillis) { Calendar calendar = GregorianCalendar.getInstance(); calendar.setTimeInMillis(timeInMillis); @@ -127,6 +142,7 @@ public class DozeUi implements DozeMachine.Part { // Alarm was canceled, but we still got the callback. Ignore. return; } + verifyLastTimeTick(); mHost.dozeTimeTick(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index c5653733bac7..28bd23ce9825 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -143,10 +143,10 @@ public class PipManager implements BasePipManager { @Override public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustement) { + Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) { mHandler.post(() -> { mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds, - fromImeAdjustement); + fromImeAdjustement, displayRotation); }); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index ac0670348af2..982b8085b216 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -221,6 +221,13 @@ public class PipMenuActivity extends Activity { } @Override + protected void onStop() { + super.onStop(); + + cancelDelayedFinish(); + } + + @Override protected void onDestroy() { super.onDestroy(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 127296cd7f8e..67255d35590a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -316,7 +316,8 @@ public class PipMotionHelper { * Animates the PiP from the expanded state to the normal state after the menu is hidden. */ void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction, - Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized) { + Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized, + boolean immediate) { if (savedSnapFraction < 0f) { // If there are no saved snap fractions, then just use the current bounds savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), @@ -326,7 +327,11 @@ public class PipMotionHelper { if (minimized) { normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); } - resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); + if (immediate) { + movePip(normalBounds); + } else { + resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 3f26fddb1b3c..a60ecf77118b 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -89,6 +89,11 @@ public class PipTouchHandler implements TunerService.Tunable { private Rect mExpandedMovementBounds = new Rect(); private int mExpandedShortestEdgeSize; + // Used to workaround an issue where the WM rotation happens before we are notified, allowing + // us to send stale bounds + private int mDeferResizeToNormalBoundsUntilRotation = -1; + private int mDisplayRotation; + private Handler mHandler = new Handler(); private Runnable mShowDismissAffordance = new Runnable() { @Override @@ -250,7 +255,7 @@ public class PipTouchHandler implements TunerService.Tunable { } public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds, - boolean fromImeAdjustement) { + boolean fromImeAdjustement, int displayRotation) { // Re-calculate the expanded bounds mNormalBounds = normalBounds; Rect normalMovementBounds = new Rect(); @@ -304,7 +309,17 @@ public class PipTouchHandler implements TunerService.Tunable { // above mNormalMovementBounds = normalMovementBounds; mExpandedMovementBounds = expandedMovementBounds; + mDisplayRotation = displayRotation; updateMovementBounds(mMenuState); + + // If we have a deferred resize, apply it now + if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) { + mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, + mNormalMovementBounds, mMovementBounds, mIsMinimized, + true /* immediate */); + mSavedSnapFraction = -1f; + mDeferResizeToNormalBoundsUntilRotation = -1; + } } private void onRegistrationChanged(boolean isRegistered) { @@ -474,11 +489,34 @@ public class PipTouchHandler implements TunerService.Tunable { // Try and restore the PiP to the closest edge, using the saved snap fraction // if possible if (resize) { - Rect normalBounds = new Rect(mNormalBounds); - mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, - mNormalMovementBounds, mMovementBounds, mIsMinimized); + // This is a very special case: when the menu is expanded and visible, navigating to + // another activity can trigger auto-enter PiP, and if the revealed activity has a + // forced rotation set, then the controller will get updated with the new rotation + // of the display. However, at the same time, SystemUI will try to hide the menu by + // creating an animation to the normal bounds which are now stale. In such a case + // we defer the animation to the normal bounds until after the next + // onMovementBoundsChanged() call to get the bounds in the new orientation + if (mDeferResizeToNormalBoundsUntilRotation == -1) { + try { + int displayRotation = mPinnedStackController.getDisplayRotation(); + if (mDisplayRotation != displayRotation) { + mDeferResizeToNormalBoundsUntilRotation = displayRotation; + } + } catch (RemoteException e) { + Log.e(TAG, "Could not get display rotation from controller"); + } + } + + if (mDeferResizeToNormalBoundsUntilRotation == -1) { + Rect normalBounds = new Rect(mNormalBounds); + mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, + mNormalMovementBounds, mMovementBounds, mIsMinimized, + false /* immediate */); + mSavedSnapFraction = -1f; + } + } else { + mSavedSnapFraction = -1f; } - mSavedSnapFraction = -1f; } mMenuState = menuState; updateMovementBounds(menuState); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index f2f0d7a5a86c..657f08be8b52 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -178,7 +178,7 @@ public class PipManager implements BasePipManager { @Override public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustement) { + Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) { mHandler.post(() -> { mDefaultPipBounds.set(normalBounds); }); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index d51fe8a2f690..53c36e69ef7e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -167,6 +167,9 @@ public class QSFooter extends LinearLayout implements if (mAlarmShowing) { builder.addFloat(mDate, "alpha", 1, 0) .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth()); + } else { + mDate.setAlpha(1); + mDateTimeGroup.setTranslationX(0); } mAnimator = builder.build(); setExpansion(mExpansionAmount); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 7518527a3093..e457d7247434 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -77,6 +77,9 @@ public class QuickStatusBarHeader extends RelativeLayout { BatteryMeterView battery = findViewById(R.id.battery); battery.setForceShowPercent(true); + // Don't show the Wi-Fi indicator here, because it is shown just below in the tile. + SignalClusterView signalCluster = findViewById(R.id.signal_cluster); + signalCluster.setForceBlockWifi(); mActivityStarter = Dependency.get(ActivityStarter.class); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 92ff17a1f029..d74e3ac656f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -128,7 +128,7 @@ public class CellularTile extends QSTileImpl<SignalState> { state.value = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.icon = ResourceIcon.get(R.drawable.ic_data_unavailable); - state.state = cb.airplaneModeEnabled || !cb.enabled ? Tile.STATE_UNAVAILABLE + state.state = cb.airplaneModeEnabled || !cb.enabled || cb.noSim ? Tile.STATE_UNAVAILABLE : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; if (state.state == Tile.STATE_ACTIVE) { state.icon = ResourceIcon.get(R.drawable.ic_data_on); @@ -161,44 +161,27 @@ public class CellularTile extends QSTileImpl<SignalState> { private static final class CallbackInfo { boolean enabled; - boolean wifiEnabled; boolean airplaneModeEnabled; - String signalContentDescription; - int dataTypeIconId; - String dataContentDescription; boolean activityIn; boolean activityOut; - String enabledDesc; boolean noSim; - boolean isDataTypeIconWide; boolean roaming; } private final class CellSignalCallback implements SignalCallback { private final CallbackInfo mInfo = new CallbackInfo(); - @Override - public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, - boolean activityIn, boolean activityOut, String description, boolean isTransient) { - mInfo.wifiEnabled = enabled; - refreshState(mInfo); - } @Override - public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) { - if (qsIcon == null) { + public void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) { + if (statusIcon == null) { // Not data sim, don't display. return; } - mInfo.enabled = qsIcon.visible; - mInfo.signalContentDescription = qsIcon.contentDescription; - mInfo.dataTypeIconId = qsType; - mInfo.dataContentDescription = typeContentDescription; + mInfo.enabled = statusIcon.visible; mInfo.activityIn = activityIn; mInfo.activityOut = activityOut; - mInfo.enabledDesc = description; - mInfo.isDataTypeIconWide = qsType != 0 && isWide; mInfo.roaming = roaming; refreshState(mInfo); } @@ -206,15 +189,6 @@ public class CellularTile extends QSTileImpl<SignalState> { @Override public void setNoSims(boolean show) { mInfo.noSim = show; - if (mInfo.noSim) { - // Make sure signal gets cleared out when no sims. - mInfo.dataTypeIconId = 0; - // Show a No SIMs description to avoid emergency calls message. - mInfo.enabled = true; - mInfo.enabledDesc = mContext.getString( - R.string.keyguard_missing_sim_message_short); - mInfo.signalContentDescription = mInfo.enabledDesc; - } refreshState(mInfo); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 2713f58272d0..0a99ee6c781f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -39,6 +39,7 @@ import android.util.Log; import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -255,6 +256,7 @@ public class NotificationGuts extends FrameLayout { } public void setExposed(boolean exposed, boolean needsFalsingProtection) { + final boolean wasExposed = mExposed; mExposed = exposed; mNeedsFalsingProtection = needsFalsingProtection; if (mExposed && mNeedsFalsingProtection) { @@ -262,6 +264,13 @@ public class NotificationGuts extends FrameLayout { } else { mHandler.removeCallbacks(mFalsingCheck); } + if (wasExposed != mExposed && mGutsContent != null) { + final View contentView = mGutsContent.getContentView(); + contentView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + if (mExposed) { + contentView.requestAccessibilityFocus(); + } + } } public boolean willBeRemoved() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java index 7928575df4d4..89251897e25f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java @@ -35,6 +35,7 @@ import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Switch; @@ -57,6 +58,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private INotificationManager mINotificationManager; private String mPkg; + private String mAppName; private int mAppUid; private List<NotificationChannel> mNotificationChannels; private NotificationChannel mSingleNotificationChannel; @@ -125,7 +127,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - String appName = mPkg; + mAppName = mPkg; Drawable pkgicon = null; CharSequence channelNameText = ""; ApplicationInfo info = null; @@ -137,7 +139,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G | PackageManager.MATCH_DIRECT_BOOT_AWARE); if (info != null) { mAppUid = info.uid; - appName = String.valueOf(pm.getApplicationLabel(info)); + mAppName = String.valueOf(pm.getApplicationLabel(info)); pkgicon = pm.getApplicationIcon(info); } } catch (PackageManager.NameNotFoundException e) { @@ -189,7 +191,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } else { channelNameText = mSingleNotificationChannel.getName(); } - ((TextView) findViewById(R.id.pkgname)).setText(appName); + ((TextView) findViewById(R.id.pkgname)).setText(mAppName); ((TextView) findViewById(R.id.channel_name)).setText(channelNameText); // Set group information if this channel has an associated group. @@ -309,6 +311,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G }); } + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (mGutsContainer != null && + event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + if (mGutsContainer.isExposed()) { + event.getText().add(mContext.getString( + R.string.notification_channel_controls_opened_accessibility, mAppName)); + } else { + event.getText().add(mContext.getString( + R.string.notification_channel_controls_closed_accessibility, mAppName)); + } + } + } + private void updateSecondaryText() { final boolean disabled = mSingleNotificationChannel != null && getSelectedImportance() == IMPORTANCE_NONE; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java index fee24b7b7645..802925a315eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java @@ -227,6 +227,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl if (mShouldShowMenu && !NotificationStackScrollLayout.isPinnedHeadsUp(view) && !mParent.areGutsExposed() + && !mParent.isDark() && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) { // Only show the menu if we're not a heads up view and guts aren't exposed. mCheckForDrag = new CheckForDrag(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index dc254f9fdc1e..b01d9cc07bf5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -24,8 +24,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.telephony.SubscriptionInfo; @@ -120,6 +118,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController private boolean mBlockWifi; private boolean mBlockEthernet; private boolean mActivityEnabled; + private boolean mForceBlockWifi; public SignalClusterView(Context context) { this(context, null); @@ -151,6 +150,16 @@ public class SignalClusterView extends LinearLayout implements NetworkController updateActivityEnabled(); } + public void setForceBlockWifi() { + mForceBlockWifi = true; + mBlockWifi = true; + if (isAttachedToWindow()) { + // Re-register to get new callbacks. + mNetworkController.removeCallback(this); + mNetworkController.addCallback(this); + } + } + @Override public void onTuningChanged(String key, String newValue) { if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) { @@ -167,7 +176,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController mBlockAirplane = blockAirplane; mBlockMobile = blockMobile; mBlockEthernet = blockEthernet; - mBlockWifi = blockWifi; + mBlockWifi = blockWifi || mForceBlockWifi; // Re-register to get new callbacks. mNetworkController.removeCallback(this); mNetworkController.addCallback(this); @@ -288,9 +297,9 @@ public class SignalClusterView extends LinearLayout implements NetworkController } @Override - public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) { + public void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) { PhoneState state = getState(subId); if (state == null) { return; @@ -300,7 +309,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController state.mMobileTypeId = statusType; state.mMobileDescription = statusIcon.contentDescription; state.mMobileTypeDescription = typeContentDescription; - state.mIsMobileTypeIconWide = statusType != 0 && isWide; state.mRoaming = roaming; state.mActivityIn = activityIn && mActivityEnabled; state.mActivityOut = activityOut && mActivityEnabled; @@ -525,7 +533,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController mWifiAirplaneSpacer.setVisibility(View.GONE); } - if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) { + if (((anyMobileVisible && firstMobileTypeId == 0) || mNoSimsVisible) && mWifiVisible) { mWifiSignalSpacer.setVisibility(View.VISIBLE); } else { mWifiSignalSpacer.setVisibility(View.GONE); @@ -636,7 +644,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController private int mMobileStrengthId = 0, mMobileTypeId = 0; private int mLastMobileStrengthId = -1; private int mLastMobileTypeId = -1; - private boolean mIsMobileTypeIconWide; private String mMobileDescription, mMobileTypeDescription; private ViewGroup mMobileGroup; @@ -692,12 +699,8 @@ public class SignalClusterView extends LinearLayout implements NetworkController // When this isn't next to wifi, give it some extra padding between the signals. mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0, 0, 0, 0); - mMobile.setPaddingRelative( - mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, - 0, 0, 0); - mMobileDark.setPaddingRelative( - mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, - 0, 0, 0); + mMobile.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0); + mMobileDark.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0); if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d", (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java index a9eb20ba3a57..6361eb6ccb89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -57,12 +57,12 @@ public class SignalDrawable extends Drawable { private static final int LEVEL_MASK = 0xff; private static final int NUM_LEVEL_SHIFT = 8; private static final int NUM_LEVEL_MASK = 0xff << NUM_LEVEL_SHIFT; - private static final int STATE_SHIFT = 16; - private static final int STATE_MASK = 0xff << STATE_SHIFT; - private static final int STATE_NONE = 0; - private static final int STATE_EMPTY = 1; - private static final int STATE_CUT = 2; - private static final int STATE_CARRIER_CHANGE = 3; + public static final int STATE_SHIFT = 16; + public static final int STATE_MASK = 0xff << STATE_SHIFT; + public static final int STATE_NONE = 0; + public static final int STATE_EMPTY = 1; + public static final int STATE_CUT = 2; + public static final int STATE_CARRIER_CHANGE = 3; private static final long DOT_DELAY = 1000; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 5591d86b5334..79191f3c2114 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -31,6 +31,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; +import android.R.style; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; @@ -93,6 +94,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -1334,7 +1336,10 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateDismissView() { - mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( + // Always inflate with a dark theme, since this sits on the scrim. + ContextThemeWrapper themedContext = new ContextThemeWrapper(mContext, + style.Theme_DeviceDefault); + mDismissView = (DismissView) LayoutInflater.from(themedContext).inflate( R.layout.status_bar_notification_dismiss_all, mStackScroller, false); mDismissView.setOnButtonClickListener(new View.OnClickListener() { @Override @@ -1920,6 +1925,7 @@ public class StatusBar extends SystemUI implements DemoMode, && (mUserSetup || mUserSwitcherController == null || !mUserSwitcherController.isSimpleUserSwitcher()) && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0) + && !mDozing && !ONLY_CORE_APPS); } @@ -4325,6 +4331,7 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); mNotificationPanel.setDark(mDozing); + updateQsExpansionEnabled(); // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock // for pulsing so the Keyguard fade-out animation scrim can take over. @@ -5868,6 +5875,9 @@ public class StatusBar extends SystemUI implements DemoMode, } final ExpandableNotificationRow row = (ExpandableNotificationRow) v; + if (row.isDark()) { + return false; + } bindGuts(row, item); NotificationGuts guts = row.getGuts(); @@ -5915,8 +5925,10 @@ public class StatusBar extends SystemUI implements DemoMode, } }); a.start(); - guts.setExposed(true /* exposed */, - mState == StatusBarState.KEYGUARD /* needsFalsingProtection */); + final boolean needsFalsingProtection = + (mState == StatusBarState.KEYGUARD && + !mAccessibilityManager.isTouchExplorationEnabled()); + guts.setExposed(true /* exposed */, needsFalsingProtection); row.closeRemoteInput(); mStackScroller.onHeightChanged(row, true /* needsAnimation */); mNotificationGutsExposed = guts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java index a456786d712f..e98dc987aa5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java @@ -110,30 +110,24 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa public void setWifiIndicators(final boolean enabled, final IconState statusIcon, final IconState qsIcon, final boolean activityIn, final boolean activityOut, final String description, boolean isTransient) { - post(new Runnable() { - @Override - public void run() { - for (SignalCallback callback : mSignalCallbacks) { - callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut, - description, isTransient); - } + post(() -> { + for (SignalCallback callback : mSignalCallbacks) { + callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut, + description, isTransient); } }); } @Override - public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon, - final int statusType, final int qsType,final boolean activityIn, + public void setMobileDataIndicators(final IconState statusIcon, + final int statusType, final boolean activityIn, final boolean activityOut, final String typeContentDescription, - final String description, final boolean isWide, final int subId, boolean roaming) { - post(new Runnable() { - @Override - public void run() { - for (SignalCallback signalCluster : mSignalCallbacks) { - signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType, - activityIn, activityOut, typeContentDescription, description, isWide, - subId, roaming); - } + final int subId, boolean roaming, boolean isEmergency) { + post(() -> { + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setMobileDataIndicators(statusIcon, statusType, + activityIn, activityOut, typeContentDescription, + subId, roaming, isEmergency); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 67b5596e34c9..4421a6ab0cfd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -244,7 +244,8 @@ public class MobileSignalController extends SignalController< return SignalDrawable.getCarrierChangeState(getNumLevels()); } else if (mCurrentState.connected) { return SignalDrawable.getState(mCurrentState.level, getNumLevels(), - mCurrentState.inetCondition == 0); + mCurrentState.inetCondition == 0 || + (mCurrentState.dataDisabled && mCurrentState.userSetup)); } else if (mCurrentState.enabled) { return SignalDrawable.getEmptyState(getNumLevels()); } else { @@ -263,24 +264,14 @@ public class MobileSignalController extends SignalController< String contentDescription = getStringIfExists(getContentDescription()); String dataContentDescription = getStringIfExists(icons.mDataContentDescription); - final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED + final boolean dataDisabled = mCurrentState.dataDisabled && mCurrentState.userSetup; // Show icon in QS when we are connected or data is disabled. - boolean showDataIcon = mCurrentState.dataConnected || dataDisabled; + boolean showDataIcon = mCurrentState.dataConnected; IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, getCurrentIconId(), contentDescription); - int qsTypeIcon = 0; - IconState qsIcon = null; - String description = null; - // Only send data sim callbacks to QS. - if (mCurrentState.dataSim) { - qsTypeIcon = showDataIcon ? icons.mQsDataType : 0; - qsIcon = new IconState(mCurrentState.enabled - && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription); - description = mCurrentState.isEmergency ? null : mCurrentState.networkName; - } boolean activityIn = mCurrentState.dataConnected && !mCurrentState.carrierNetworkChangeMode && mCurrentState.activityIn; @@ -289,9 +280,10 @@ public class MobileSignalController extends SignalController< && mCurrentState.activityOut; showDataIcon &= mCurrentState.isDefault || dataDisabled; int typeIcon = showDataIcon ? icons.mDataType : 0; - callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon, - activityIn, activityOut, dataContentDescription, description, icons.mIsWide, - mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming); + callback.setMobileDataIndicators(statusIcon, typeIcon, + activityIn, activityOut, dataContentDescription, + mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming, + mCurrentState.isEmergency); } @Override @@ -438,14 +430,14 @@ public class MobileSignalController extends SignalController< } else { mCurrentState.iconGroup = mDefaultIcons; } + mCurrentState.dataDisabled = isDataDisabled(); mCurrentState.dataConnected = mCurrentState.connected - && mDataState == TelephonyManager.DATA_CONNECTED; + && mDataState == TelephonyManager.DATA_CONNECTED + && !mCurrentState.dataDisabled; mCurrentState.roaming = isRoaming(); if (isCarrierNetworkChangeActive()) { mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; - } else if (isDataDisabled()) { - mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED; } if (isEmergencyOnly() != mCurrentState.isEmergency) { mCurrentState.isEmergency = isEmergencyOnly(); @@ -577,6 +569,7 @@ public class MobileSignalController extends SignalController< boolean isDefault; boolean userSetup; boolean roaming; + boolean dataDisabled; @Override public void copyFrom(State s) { @@ -592,6 +585,7 @@ public class MobileSignalController extends SignalController< carrierNetworkChangeMode = state.carrierNetworkChangeMode; userSetup = state.userSetup; roaming = state.roaming; + dataDisabled = state.dataDisabled; } @Override @@ -609,6 +603,7 @@ public class MobileSignalController extends SignalController< builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) .append(','); builder.append("userSetup=").append(userSetup); + builder.append("dataDisabled=").append(dataDisabled); } @Override @@ -623,6 +618,7 @@ public class MobileSignalController extends SignalController< && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode && ((MobileState) o).userSetup == userSetup && ((MobileState) o).isDefault == isDefault + && ((MobileState) o).dataDisabled == dataDisabled && ((MobileState) o).roaming == roaming; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index c02ce0ea6335..ab4a8f21ba24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -48,9 +48,9 @@ public interface NetworkController extends CallbackController<SignalCallback>, D default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient) {} - default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) {} + default void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) {} default void setSubs(List<SubscriptionInfo> subs) {} default void setNoSims(boolean show) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index c21f444d0bf3..60f4ab8ffe0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -867,7 +867,6 @@ public class NetworkControllerImpl extends BroadcastReceiver datatype.equals("h") ? TelephonyIcons.H : datatype.equals("lte") ? TelephonyIcons.LTE : datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : - datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : TelephonyIcons.UNKNOWN; } if (args.containsKey("roam")) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index aaa0568a72cd..ec7e557fde81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -44,10 +44,6 @@ class TelephonyIcons { static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus; static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x; - static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled; - - static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled; - static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup( "CARRIER_NETWORK_CHANGE", null, @@ -221,20 +217,5 @@ class TelephonyIcons { true, TelephonyIcons.QS_DATA_LTE_PLUS ); - - static final MobileIconGroup DATA_DISABLED = new MobileIconGroup( - "DataDisabled", - null, - null, - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, - 0, 0, - 0, - 0, - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], - R.string.accessibility_cell_data_off, - TelephonyIcons.ICON_DATA_DISABLED, - false, - TelephonyIcons.QS_ICON_DATA_DISABLED - ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java index 374408d3ec7a..dfc3591678ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java @@ -47,6 +47,7 @@ public class WifiIcons { static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network; static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null; + static final int WIFI_DISCONNECTED = R.drawable.stat_sys_wifi_signal_disconnected; static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 2104cb1421aa..a773acf317c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -80,7 +80,7 @@ public class WifiSignalController extends AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH, WifiIcons.WIFI_NO_NETWORK, WifiIcons.QS_WIFI_NO_NETWORK, - WifiIcons.WIFI_NO_NETWORK, + WifiIcons.WIFI_DISCONNECTED, WifiIcons.QS_WIFI_NO_NETWORK, AccessibilityContentDescriptions.WIFI_NO_CONNECTION ); @@ -133,8 +133,7 @@ public class WifiSignalController extends @Override public void notifyListeners(SignalCallback callback) { // only show wifi in the cluster if connected or if wifi-only - boolean wifiVisible = mCurrentState.enabled - && (mCurrentState.connected || !mHasMobileData); + boolean wifiVisible = true; String wifiDesc = wifiVisible ? mCurrentState.ssid : null; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; String contentDescription = getStringIfExists(getContentDescription()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java index 3ed1681644f2..f6c75a8f0b84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java @@ -114,33 +114,26 @@ public class CallbackHandlerTest { boolean wide = true; int subId = 5; boolean roaming = true; - mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription, - description, wide, subId, roaming); + boolean isEmergency = true; + mHandler.setMobileDataIndicators(status, type, in, out, typeDescription, + subId, roaming, isEmergency); waitForCallbacks(); ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class); - ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<String> typeContentArg = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class); Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(), - qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(), - outArg.capture(), typeContentArg.capture(), descArg.capture(), wideArg.capture(), - subIdArg.capture(), eq(roaming)); + typeIconArg.capture(), inArg.capture(), + outArg.capture(), typeContentArg.capture(), + subIdArg.capture(), eq(roaming), eq(isEmergency)); assertEquals(status, statusArg.getValue()); - assertEquals(qs, qsArg.getValue()); assertEquals(type, (int) typeIconArg.getValue()); - assertEquals(qsType, (int) qsTypeIconArg.getValue()); assertEquals(in, (boolean) inArg.getValue()); assertEquals(out, (boolean) outArg.getValue()); assertEquals(typeDescription, typeContentArg.getValue()); - assertEquals(description, descArg.getValue()); - assertEquals(wide, (boolean) wideArg.getValue()); assertEquals(subId, (int) subIdArg.getValue()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 505e1d8346fd..b39171e9f720 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -29,6 +29,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; + import com.android.internal.telephony.cdma.EriInfo; import com.android.settingslib.net.DataUsageController; import com.android.systemui.statusbar.phone.SignalDrawable; @@ -45,8 +46,6 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import java.io.PrintWriter; import java.io.StringWriter; @@ -70,7 +69,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected static final int DEFAULT_SIGNAL_STRENGTH = DEFAULT_LEVEL; protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL; protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G; - protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_DATA_3G; + protected static final int DEFAULT_QS_ICON = DEFAULT_ICON; protected NetworkControllerImpl mNetworkController; protected MobileSignalController mMobileSignalController; @@ -117,7 +116,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn( - new NetworkCapabilities[] { mNetCapabilities }); + new NetworkCapabilities[]{mNetCapabilities}); mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); @@ -175,17 +174,17 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected NetworkControllerImpl setUpNoMobileData() { - when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); - NetworkControllerImpl networkControllerNoMobile - = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm, - mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler, - mock(AccessPointControllerImpl.class), - mock(DataUsageController.class), mMockSubDefaults, - mock(DeviceProvisionedController.class)); + when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); + NetworkControllerImpl networkControllerNoMobile + = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm, + mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), + mock(DataUsageController.class), mMockSubDefaults, + mock(DeviceProvisionedController.class)); - setupNetworkController(); + setupNetworkController(); - return networkControllerNoMobile; + return networkControllerNoMobile; } @@ -308,11 +307,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase { ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( - any(), - iconArg.capture(), - anyInt(), - typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), - anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); + iconArg.capture(), + typeIconArg.capture(), + dataInArg.capture(), dataOutArg.capture(), + anyString(), anyInt(), anyBoolean(), anyBoolean()); IconState iconState = iconArg.getValue(); int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, false); @@ -335,17 +333,16 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, - boolean roaming, boolean inet) { + boolean roaming, boolean inet) { ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); // TODO: Verify all fields. Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( iconArg.capture(), - any(), typeIconArg.capture(), - anyInt(), anyBoolean(), anyBoolean(), anyString(), anyString(), anyBoolean(), - anyInt(), eq(roaming)); + anyBoolean(), anyBoolean(), anyString(), + anyInt(), eq(roaming), anyBoolean()); IconState iconState = iconArg.getValue(); int state = icon == -1 ? 0 @@ -356,22 +353,18 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, - boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut) { + boolean qsVisible, boolean dataIn, boolean dataOut) { ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class); - ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( iconArg.capture(), - qsIconArg.capture(), typeIconArg.capture(), - qsTypeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), - anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); + anyString(), anyInt(), anyBoolean(), anyBoolean()); IconState iconState = iconArg.getValue(); @@ -381,17 +374,15 @@ public class NetworkControllerBaseTest extends SysuiTestCase { assertEquals("Signal icon in status bar", state, iconState.icon); assertEquals("Visibility in status bar", visible, iconState.visible); - iconState = qsIconArg.getValue(); assertEquals("Visibility in quick settings", qsVisible, iconState.visible); assertEquals("Signal icon in quick settings", state, iconState.icon); - assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue()); assertEquals("Data direction in in quick settings", dataIn, (boolean) dataInArg.getValue()); assertEquals("Data direction out in quick settings", dataOut, (boolean) dataOutArg.getValue()); } - protected void assertNetworkNameEquals(String expected) { - assertEquals("Network name", expected, mMobileSignalController.getState().networkName); - } + protected void assertNetworkNameEquals(String expected) { + assertEquals("Network name", expected, mMobileSignalController.getState().networkName); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index dfe00f95fe4d..6470c117f406 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -1,5 +1,9 @@ package com.android.systemui.statusbar.policy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -11,10 +15,14 @@ import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import com.android.settingslib.net.DataUsageController; +import com.android.systemui.statusbar.phone.SignalDrawable; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; @SmallTest @RunWith(AndroidJUnit4.class) @@ -116,8 +124,11 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0); setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); - verifyDataIndicators(TelephonyIcons.ICON_DATA_DISABLED, - TelephonyIcons.QS_ICON_DATA_DISABLED); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), anyInt(), anyBoolean(), anyBoolean(), any(), anyInt(), + anyBoolean(), anyBoolean()); + assertEquals(SignalDrawable.STATE_CUT, SignalDrawable.getState(iconArg.getValue().icon)); } @Test @@ -129,9 +140,14 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(false); mUserCallback.onUserSetupChanged(); + waitForIdleSync(); // Don't show the X until the device is setup. - verifyDataIndicators(0, 0); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), anyInt(), anyBoolean(), anyBoolean(), any(), anyInt(), + anyBoolean(), anyBoolean()); + assertNotEquals(SignalDrawable.STATE_CUT, SignalDrawable.getState(iconArg.getValue().icon)); } @Test @@ -181,12 +197,12 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataActivity(direction); verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON, true, - DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out); + in, out); } private void verifyDataIndicators(int dataIcon, int qsDataIcon) { verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon, - true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false, + true, false, false); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 1627925ae1bc..e542c371feda 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -214,7 +214,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { verifyLastQsMobileDataIndicators(true, testStrength, - TelephonyIcons.QS_DATA_1X, false, false); + TelephonyIcons.ICON_1X, false, false); } } @@ -434,7 +434,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { verifyLastQsMobileDataIndicators(true /* visible */, DEFAULT_LEVEL /* icon */, - DEFAULT_QS_ICON /* typeIcon */, + DEFAULT_ICON /* typeIcon */, false /* dataIn */, true /* dataOut */); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 73fa5aa180bf..edfa3261a7e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -62,7 +62,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { public void testWifiIcon() { String testSsid = "Test SSID"; setWifiEnabled(true); - verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); + verifyLastWifiIcon(true, WifiIcons.WIFI_DISCONNECTED); setWifiState(true, testSsid); verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 5feb81db4a0b..7c3f3245461c 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -68,6 +68,7 @@ import com.android.server.autofill.ui.AutoFillUI; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; @@ -220,6 +221,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { mActivityToken = newActivity; mClient = IAutoFillManagerClient.Stub.asInterface(newClient); + + // The tracked id are not persisted in the client, hence update them + updateTrackedIdsLocked(); } } @@ -749,6 +753,38 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + private void updateTrackedIdsLocked() { + if (mResponses == null || mResponses.size() == 0) { + return; + } + + // Only track the views of the last response as only those are reported back to the + // service, see #showSaveLocked + ArrayList<AutofillId> trackedViews = new ArrayList<>(); + boolean saveOnAllViewsInvisible = false; + SaveInfo saveInfo = mResponses.valueAt(getLastResponseIndex()).getSaveInfo(); + if (saveInfo != null) { + saveOnAllViewsInvisible = saveInfo.saveOnAllViewsInvisible(); + + // We only need to track views if we want to save once they become invisible. + if (saveOnAllViewsInvisible) { + if (saveInfo.getRequiredIds() != null) { + Collections.addAll(trackedViews, saveInfo.getRequiredIds()); + } + + if (saveInfo.getOptionalIds() != null) { + Collections.addAll(trackedViews, saveInfo.getOptionalIds()); + } + } + } + + try { + mClient.setTrackedViews(id, trackedViews, saveOnAllViewsInvisible); + } catch (RemoteException e) { + Slog.w(TAG, "Cannot set tracked ids", e); + } + } + private void processResponseLocked(FillResponse response, int requestId) { if (DEBUG) { Slog.d(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response); @@ -763,6 +799,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } setViewStatesLocked(response, ViewState.STATE_FILLABLE); + updateTrackedIdsLocked(); if (mCurrentViewId == null) { return; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d79609856c3f..452fe1d70ddc 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3272,6 +3272,8 @@ class StorageManagerService extends IStorageManager.Stub try { return mContext.getSystemService(StorageStatsManager.class) .queryStatsForUid(volumeUuid, uid).getCacheBytes(); + } catch (IOException e) { + throw new ParcelableException(e); } finally { Binder.restoreCallingIdentity(token); } @@ -3312,6 +3314,8 @@ class StorageManagerService extends IStorageManager.Stub return Math.max(0, path.getUsableSpace() - storage.getStorageLowBytes(path)); } } + } catch (IOException e) { + throw new ParcelableException(e); } finally { Binder.restoreCallingIdentity(token); } @@ -3329,13 +3333,13 @@ class StorageManagerService extends IStorageManager.Stub + " because only " + allocatableBytes + " allocatable")); } - // Free up enough disk space to satisfy both the requested allocation - // and our low disk warning space. - final File path = storage.findPathForUuid(volumeUuid); - bytes += storage.getStorageLowBytes(path); - final long token = Binder.clearCallingIdentity(); try { + // Free up enough disk space to satisfy both the requested allocation + // and our low disk warning space. + final File path = storage.findPathForUuid(volumeUuid); + bytes += storage.getStorageLowBytes(path); + mPms.freeStorage(volumeUuid, bytes, flags); } catch (IOException e) { throw new ParcelableException(e); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6b0a73b25e71..fa936c209099 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1230,6 +1230,20 @@ public class ActivityManagerService extends IActivityManager.Stub */ int[] mDeviceIdleTempWhitelist = new int[0]; + static final class PendingTempWhitelist { + final int targetUid; + final long duration; + final String tag; + + PendingTempWhitelist(int _targetUid, long _duration, String _tag) { + targetUid = _targetUid; + duration = _duration; + tag = _tag; + } + } + + final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>(); + /** * Information about and control over application operations */ @@ -1688,6 +1702,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int NOTIFY_VR_SLEEPING_MSG = 65; static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67; + static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int START_USER_SWITCH_FG_MSG = 712; static final int FIRST_ACTIVITY_STACK_MSG = 100; @@ -1921,6 +1936,9 @@ public class ActivityManagerService extends IActivityManager.Stub case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; + case PUSH_TEMP_WHITELIST_UI_MSG: { + pushTempWhitelist(); + } break; } } } @@ -6493,7 +6511,8 @@ public class ActivityManagerService extends IActivityManager.Stub // This is the first appearance of the uid, report it now! if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Creating new process uid: " + uidRec); - if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0) { + if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0 + || mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) { uidRec.setWhitelist = uidRec.curWhitelist = true; } uidRec.updateHasInternetPermission(); @@ -7487,43 +7506,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - /** - * Whitelists {@code targetUid} to temporarily bypass Power Save mode. - */ - void tempWhitelistAppForPowerSave(int callerPid, int callerUid, int targetUid, long duration) { - if (DEBUG_WHITELISTS) { - Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", " - + targetUid + ", " + duration + ")"); - } - - if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) - != PackageManager.PERMISSION_GRANTED) { - synchronized (mPidsSelfLocked) { - final ProcessRecord pr = mPidsSelfLocked.get(callerPid); - if (pr == null) { - Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " - + callerPid); - return; - } - if (!pr.whitelistManager) { - if (DEBUG_WHITELISTS) { - Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid - + ": pid " + callerPid + " is not allowed"); - } - return; - } - } - } - - final long token = Binder.clearCallingIdentity(); - try { - mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(targetUid, duration, - true, "pe from uid:" + callerUid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - @Override public void cancelIntentSender(IIntentSender sender) { if (!(sender instanceof PendingIntentRecord)) { @@ -8412,7 +8394,8 @@ public class ActivityManagerService extends IActivityManager.Stub boolean isOnDeviceIdleWhitelistLocked(int uid) { final int appId = UserHandle.getAppId(uid); return Arrays.binarySearch(mDeviceIdleWhitelist, appId) >= 0 - || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0; + || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0 + || mPendingTempWhitelist.indexOfKey(uid) >= 0; } private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) { @@ -10535,8 +10518,9 @@ public class ActivityManagerService extends IActivityManager.Stub final PinnedActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID); if (pinnedStack != null) { - pinnedStack.animateResizePinnedStack(null /* sourceBounds */, - destBounds, animationDuration); + pinnedStack.animateResizePinnedStack(null /* sourceHintBounds */, + destBounds, animationDuration, + false /* schedulePipModeChangedOnAnimationEnd */); } } else { throw new IllegalArgumentException("Stack: " + stackId @@ -15587,6 +15571,18 @@ public class ActivityManagerService extends IActivityManager.Stub } pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist)); pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist)); + if (mPendingTempWhitelist.size() > 0) { + pw.println(" mPendingTempWhitelist:"); + for (int i = 0; i < mPendingTempWhitelist.size(); i++) { + PendingTempWhitelist ptw = mPendingTempWhitelist.valueAt(i); + pw.print(" "); + UserHandle.formatUid(pw, ptw.targetUid); + pw.print(": "); + TimeUtils.formatDuration(ptw.duration, pw); + pw.print(" "); + pw.println(ptw.tag); + } + } } if (dumpPackage == null) { pw.println(" mWakefulness=" @@ -22699,6 +22695,80 @@ public class ActivityManagerService extends IActivityManager.Stub enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE); } + /** + * Whitelists {@code targetUid} to temporarily bypass Power Save mode. + */ + void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid, + long duration, String tag) { + if (DEBUG_WHITELISTS) { + Slog.d(TAG, "tempWhitelistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", " + + targetUid + ", " + duration + ")"); + } + + synchronized (mPidsSelfLocked) { + final ProcessRecord pr = mPidsSelfLocked.get(callerPid); + if (pr == null) { + Slog.w(TAG, "tempWhitelistForPendingIntentLocked() no ProcessRecord for pid " + + callerPid); + return; + } + if (!pr.whitelistManager) { + if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) + != PackageManager.PERMISSION_GRANTED) { + if (DEBUG_WHITELISTS) { + Slog.d(TAG, "tempWhitelistForPendingIntentLocked() for target " + targetUid + + ": pid " + callerPid + " is not allowed"); + } + return; + } + } + } + + tempWhitelistUidLocked(targetUid, duration, tag); + } + + /** + * Whitelists {@code targetUid} to temporarily bypass Power Save mode. + */ + void tempWhitelistUidLocked(int targetUid, long duration, String tag) { + mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag)); + setUidTempWhitelistStateLocked(targetUid, true); + mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget(); + } + + void pushTempWhitelist() { + final int N; + final PendingTempWhitelist[] list; + + // First copy out the pending changes... we need to leave them in the map for now, + // in case someone needs to check what is coming up while we don't have the lock held. + synchronized(this) { + N = mPendingTempWhitelist.size(); + list = new PendingTempWhitelist[N]; + for (int i = 0; i < N; i++) { + list[i] = mPendingTempWhitelist.valueAt(i); + } + } + + // Now safely dispatch changes to device idle controller. + for (int i = 0; i < N; i++) { + PendingTempWhitelist ptw = list[i]; + mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid, + ptw.duration, true, ptw.tag); + } + + // And now we can safely remove them from the map. + synchronized(this) { + for (int i = 0; i < N; i++) { + PendingTempWhitelist ptw = list[i]; + int index = mPendingTempWhitelist.indexOfKey(ptw.targetUid); + if (index >= 0 && mPendingTempWhitelist.valueAt(index) == ptw) { + mPendingTempWhitelist.removeAt(index); + } + } + } + } + final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) { boolean changed = false; for (int i=mActiveUids.size()-1; i>=0; i--) { @@ -22713,6 +22783,15 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) { + boolean changed = false; + final UidRecord uidRec = mActiveUids.get(uid); + if (uidRec != null && uidRec.curWhitelist != onWhitelist) { + uidRec.curWhitelist = onWhitelist; + updateOomAdjLocked(); + } + } + final void trimApplications() { synchronized (this) { int i; diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 28817878373b..494aaa766b94 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -314,7 +314,8 @@ class ActivityMetricsLogger { builder.setPackageName(info.launchedActivity.packageName); builder.setType(type); builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name); - if (info.launchedActivity.launchedFromPackage != null) { + final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp(); + if (isInstantApp && info.launchedActivity.launchedFromPackage != null) { builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME, info.launchedActivity.launchedFromPackage); } @@ -323,8 +324,7 @@ class ActivityMetricsLogger { info.launchedActivity.info.launchToken); info.launchedActivity.info.launchToken = null; } - builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, - info.launchedActivity.info.applicationInfo.isInstantApp() ? 1 : 0); + builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0); builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS, mCurrentTransitionDeviceUptime); builder.addTaggedData(APP_TRANSITION_DELAY_MS, mCurrentTransitionDelayMs); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4c84d98d468a..825e8ac0a698 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -589,6 +589,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** + * Returns whether to defer the scheduling of the multi-window mode. + */ + boolean deferScheduleMultiWindowModeChanged() { + return false; + } + + /** * Defers updating the bounds of the stack. If the stack was resized/repositioned while * deferring, the bounds will update in {@link #continueUpdateBounds()}. */ diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 4d16e33ad81c..43ae4b22ba63 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2504,7 +2504,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting // for the AMS lock to be freed. So check and make sure these bounds are still good. final PinnedStackWindowController stackController = stack.getWindowContainerController(); - if (stackController.pinnedStackResizeAllowed()) { + if (stackController.pinnedStackResizeDisallowed()) { return; } @@ -2873,7 +2873,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceBounds, float aspectRatio, + void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceHintBounds, float aspectRatio, boolean moveHomeStackToFront, String reason) { mWindowManager.deferSurfaceLayout(); @@ -2948,11 +2948,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final Rect destBounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY, aspectRatio, false /* useExistingStackBounds */); - // TODO(b/36099777): Schedule the PiP mode change here immediately until we can defer all - // callbacks until after the bounds animation - scheduleUpdatePictureInPictureModeIfNeeded(r.getTask(), destBounds, true /* immediate */); - - stack.animateResizePinnedStack(sourceBounds, destBounds, -1 /* animationDuration */); + stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */, + true /* schedulePipModeChangedOnAnimationEnd */); mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName); } @@ -4179,6 +4176,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void scheduleUpdateMultiWindowMode(TaskRecord task) { + // If the stack is animating in a way where we will be forcing a multi-mode change at the + // end, then ensure that we defer all in between multi-window mode changes + if (task.getStack().deferScheduleMultiWindowModeChanged()) { + return; + } + for (int i = task.mActivities.size() - 1; i >= 0; i--) { final ActivityRecord r = task.mActivities.get(i); if (r.app != null && r.app.thread != null) { diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java index 02ec07561f4f..c9c1d005a85a 100644 --- a/services/core/java/com/android/server/am/AppErrorDialog.java +++ b/services/core/java/com/android/server/am/AppErrorDialog.java @@ -148,18 +148,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { - final int result = msg.what; - - synchronized (mService) { - if (mProc != null && mProc.crashDialog == AppErrorDialog.this) { - mProc.crashDialog = null; - } - } - mResult.set(result); - - // Make sure we don't have time timeout still hanging around. - removeMessages(TIMEOUT); - + setResult(msg.what); dismiss(); } }; @@ -168,11 +157,23 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen public void dismiss() { if (!mResult.mHasResult) { // We are dismissing and the result has not been set...go ahead and set. - mResult.set(FORCE_QUIT); + setResult(FORCE_QUIT); } super.dismiss(); } + private void setResult(int result) { + synchronized (mService) { + if (mProc != null && mProc.crashDialog == AppErrorDialog.this) { + mProc.crashDialog = null; + } + } + mResult.set(result); + + // Make sure we don't have time timeout still hanging around. + mHandler.removeMessages(TIMEOUT); + } + @Override public void onClick(View v) { switch (v.getId()) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index baa71d708caa..349180fd28a9 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -155,8 +155,6 @@ public final class BroadcastQueue { static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG; static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; - static final int SCHEDULE_TEMP_WHITELIST_MSG - = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 2; final BroadcastHandler mHandler; @@ -178,13 +176,6 @@ public final class BroadcastQueue { broadcastTimeoutLocked(true); } } break; - case SCHEDULE_TEMP_WHITELIST_MSG: { - DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController; - if (dic != null) { - dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1), - msg.arg2, true, (String)msg.obj); - } - } break; } } } @@ -789,12 +780,11 @@ public final class BroadcastQueue { if (r.intent.getAction() != null) { b.append(r.intent.getAction()); } else if (r.intent.getComponent() != null) { - b.append(r.intent.getComponent().flattenToShortString()); + r.intent.getComponent().appendShortString(b); } else if (r.intent.getData() != null) { b.append(r.intent.getData()); } - mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration, b.toString()) - .sendToTarget(); + mService.tempWhitelistUidLocked(uid, duration, b.toString()); } /** diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index c697f2876c65..a580d4bdde5e 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -237,14 +237,6 @@ final class PendingIntentRecord extends IIntentSender.Stub { if (intent != null) intent.setDefusable(true); if (options != null) options.setDefusable(true); - if (whitelistDuration > 0 && !canceled) { - // Must call before acquiring the lock. It's possible the method return before sending - // the intent due to some validations inside the lock, in which case the UID shouldn't - // be whitelisted, but since the whitelist is temporary, that would be ok. - owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid, - whitelistDuration); - } - synchronized (owner) { final ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null && activityContainer.mParentActivity != null && @@ -279,6 +271,22 @@ final class PendingIntentRecord extends IIntentSender.Stub { resolvedType = key.requestResolvedType; } + if (whitelistDuration > 0) { + StringBuilder tag = new StringBuilder(64); + tag.append("pendingintent:"); + UserHandle.formatUid(tag, Binder.getCallingUid()); + tag.append(":"); + if (finalIntent.getAction() != null) { + tag.append(finalIntent.getAction()); + } else if (finalIntent.getComponent() != null) { + finalIntent.getComponent().appendShortString(tag); + } else if (finalIntent.getData() != null) { + tag.append(finalIntent.getData()); + } + owner.tempWhitelistForPendingIntentLocked(Binder.getCallingPid(), + Binder.getCallingUid(), uid, whitelistDuration, tag.toString()); + } + final long origId = Binder.clearCallingIdentity(); boolean sendFinish = finishedReceiver != null; diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java index cd9c42c7c643..a4932bbdd732 100644 --- a/services/core/java/com/android/server/am/PinnedActivityStack.java +++ b/services/core/java/com/android/server/am/PinnedActivityStack.java @@ -43,9 +43,10 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds); } - void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, int animationDuration) { - getWindowContainerController().animateResizePinnedStack(sourceBounds, destBounds, - animationDuration); + void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration, + boolean schedulePipModeChangedOnAnimationEnd) { + getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds, + animationDuration, schedulePipModeChangedOnAnimationEnd); } void setPictureInPictureAspectRatio(float aspectRatio) { @@ -60,7 +61,18 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> return getWindowContainerController().isAnimatingBoundsToFullscreen(); } - @Override + /** + * Returns whether to defer the scheduling of the multi-window mode. + */ + boolean deferScheduleMultiWindowModeChanged() { + // For the pinned stack, the deferring of the multi-window mode changed is tied to the + // transition animation into picture-in-picture, and is called once the animation completes, + // or is interrupted in a way that would leave the stack in a non-fullscreen state. + // @see BoundsAnimationController + // @see BoundsAnimationControllerTests + return mWindowContainerController.deferScheduleMultiWindowModeChanged(); + } + public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) { // It is guaranteed that the activities requiring the update will be in the pinned stack at // this point (either reparented before the animation into PiP, or before reparenting after diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 53a8092fa558..cd70c7877041 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -1142,38 +1142,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } - public void addQueueItem(MediaDescription description) { - try { - mCb.onAddQueueItem(description); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in addQueueItem.", e); - } - } - - public void addQueueItemAt(MediaDescription description, int index) { - try { - mCb.onAddQueueItemAt(description, index); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in addQueueItemAt.", e); - } - } - - public void removeQueueItem(MediaDescription description) { - try { - mCb.onRemoveQueueItem(description); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in removeQueueItem.", e); - } - } - - public void removeQueueItemAt(int index) { - try { - mCb.onRemoveQueueItemAt(index); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in removeQueueItem.", e); - } - } - public void adjustVolume(int direction) { try { mCb.onAdjustVolume(direction); @@ -1449,30 +1417,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void addQueueItem(MediaDescription description) { - updateCallingPackage(); - mSessionCb.addQueueItem(description); - } - - @Override - public void addQueueItemAt(MediaDescription description, int index) { - updateCallingPackage(); - mSessionCb.addQueueItemAt(description, index); - } - - @Override - public void removeQueueItem(MediaDescription description) { - updateCallingPackage(); - mSessionCb.removeQueueItem(description); - } - - @Override - public void removeQueueItemAt(int index) { - updateCallingPackage(); - mSessionCb.removeQueueItemAt(index); - } - - @Override public CharSequence getQueueTitle() { return mQueueTitle; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f334ba41bdf1..cc3948ed1a59 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -97,6 +97,7 @@ import android.media.AudioManagerInternal; import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -1322,7 +1323,8 @@ public class NotificationManagerService extends SystemService { if (!fromListener) { mListeners.notifyNotificationChannelChanged( - pkg, modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); + pkg, UserHandle.getUserHandleForUid(uid), + modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); } synchronized (mNotificationLock) { @@ -1647,7 +1649,8 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(group, "group in list is null"); mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true /* fromTargetApp */); - mListeners.notifyNotificationChannelGroupChanged(pkg, group, + mListeners.notifyNotificationChannelGroupChanged(pkg, + UserHandle.of(UserHandle.getCallingUserId()), group, NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } savePolicyFile(); @@ -1663,6 +1666,7 @@ public class NotificationManagerService extends SystemService { mRankingHelper.createNotificationChannel(pkg, uid, channel, true /* fromTargetApp */); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(uid), mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } @@ -1708,6 +1712,7 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); @@ -1737,11 +1742,14 @@ public class NotificationManagerService extends SystemService { true, UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); - mListeners.notifyNotificationChannelChanged(pkg, deletedChannel, + mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), + deletedChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } mListeners.notifyNotificationChannelGroupChanged( - pkg, groupToDelete, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); + pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, + NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); } } @@ -2691,43 +2699,59 @@ public class NotificationManagerService extends SystemService { @Override public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, - String pkg, NotificationChannel channel) throws RemoteException { + String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { Preconditions.checkNotNull(channel); + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } - - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - updateNotificationChannelInt(pkg, uid, channel, true); + verifyPrivilegedListener(token, user); + updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); } @Override public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */); + return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), + false /* includeDeleted */); } @Override public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); + + List<NotificationChannelGroup> groups = new ArrayList<>(); + groups.addAll(mRankingHelper.getNotificationChannelGroups( + pkg, getUidForPackageAndUser(pkg, user))); + return new ParceledListSlice<>(groups); + } + + private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); if (!hasCompanionDevice(info)) { throw new SecurityException(info + " does not have access"); } + if (!info.enabledAndUserMatches(user.getIdentifier())) { + throw new SecurityException(info + " does not have access"); + } + } - List<NotificationChannelGroup> groups = new ArrayList<>(); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - groups.addAll(mRankingHelper.getNotificationChannelGroups(pkg, uid)); - return new ParceledListSlice<>(groups); + private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { + int uid = 0; + long identity = Binder.clearCallingIdentity(); + try { + uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); + } finally { + Binder.restoreCallingIdentity(identity); + } + return uid; } }; @@ -3162,16 +3186,16 @@ public class NotificationManagerService extends SystemService { // STOPSHIP TODO: should throw instead of logging or toasting. // throw new IllegalArgumentException(noChannelStr); Log.e(TAG, noChannelStr); - - final String noChannelToastStr = - "Developer warning for package \"" + pkg + "\"\n" + + doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" + "Failed to post notification on channel \"" + channelId + "\"\n" + - "See log for more details"; - Toast noChannelToast = - Toast.makeText(getContext(), noChannelToastStr, Toast.LENGTH_LONG); - noChannelToast.show(); + "See log for more details"); return; + } else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) { + // STOPSHIP TODO: remove once default channel is removed for all apps that target O. + doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" + + "Posted notification should specify a channel"); } + final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, notificationUid, callingPid, notification, user, null, System.currentTimeMillis()); @@ -3203,6 +3227,26 @@ public class NotificationManagerService extends SystemService { idOut[0] = id; } + private void doDebugOnlyToast(CharSequence toastText) { + if (Build.IS_DEBUGGABLE) { + Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG); + toast.show(); + } + } + + // STOPSHIP - Remove once RankingHelper deletes default channel for all apps targeting O. + private boolean shouldWarnUseChannels(String pkg, int uid) { + try { + final int userId = UserHandle.getUserId(uid); + final ApplicationInfo applicationInfo = + mPackageManagerClient.getApplicationInfoAsUser(pkg, 0, userId); + return applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1; + } catch (NameNotFoundException e) { + Slog.e(TAG, e.toString()); + return false; + } + } + private int resolveNotificationUid(String opPackageName, int callingUid, int userId) { // The system can post notifications on behalf of any package it wants if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) { @@ -5019,7 +5063,7 @@ public class NotificationManagerService extends SystemService { } } - protected void notifyNotificationChannelChanged(final String pkg, + protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { if (channel == null) { return; @@ -5034,15 +5078,16 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelChanged(serviceInfo, pkg, channel, - modificationType); + notifyNotificationChannelChanged( + serviceInfo, pkg, user, channel, modificationType); } }); } } - protected void notifyNotificationChannelGroupChanged(final String pkg, - final NotificationChannelGroup group, final int modificationType) { + protected void notifyNotificationChannelGroupChanged( + final String pkg, final UserHandle user, final NotificationChannelGroup group, + final int modificationType) { if (group == null) { return; } @@ -5056,8 +5101,8 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelGroupChanged(serviceInfo, pkg, group, - modificationType); + notifyNotificationChannelGroupChanged( + serviceInfo, pkg, user, group, modificationType); } }); } @@ -5118,22 +5163,22 @@ public class NotificationManagerService extends SystemService { } void notifyNotificationChannelChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannel channel, + final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelModification(pkg, channel, modificationType); + listener.onNotificationChannelModification(pkg, user, channel, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex); } } private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannelGroup group, + final String pkg, final UserHandle user, final NotificationChannelGroup group, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelGroupModification(pkg, group, modificationType); + listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e79f46b4f3be..95b4903e49d7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -364,7 +364,8 @@ import java.util.concurrent.atomic.AtomicInteger; * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases * </pre> */ -public class PackageManagerService extends IPackageManager.Stub { +public class PackageManagerService extends IPackageManager.Stub + implements PackageSender { static final String TAG = "PackageManager"; static final boolean DEBUG_SETTINGS = false; static final boolean DEBUG_PREFERRED = false; @@ -13083,7 +13084,7 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - final void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, + public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds) { mHandler.post(new Runnable() { @@ -13386,8 +13387,7 @@ public class PackageManagerService extends IPackageManager.Stub { sendPackageAddedForNewUsers(packageName, isSystem, pkgSetting.appId, userId); } - private void sendPackageAddedForNewUsers(String packageName, boolean isSystem, - int appId, int... userIds) { + public void sendPackageAddedForNewUsers(String packageName, boolean isSystem, int appId, int... userIds) { if (ArrayUtils.isEmpty(userIds)) { return; } @@ -13514,7 +13514,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { - final PackageRemovedInfo info = new PackageRemovedInfo(); + final PackageRemovedInfo info = new PackageRemovedInfo(this); info.removedPackage = packageName; info.removedUsers = new int[] {userId}; info.broadcastUsers = new int[] {userId}; @@ -16150,7 +16150,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Update what is removed - res.removedInfo = new PackageRemovedInfo(); + res.removedInfo = new PackageRemovedInfo(this); res.removedInfo.uid = oldPackage.applicationInfo.uid; res.removedInfo.removedPackage = oldPackage.packageName; res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null; @@ -16180,7 +16180,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } if (!childPackageUpdated) { - PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(); + PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this); childRemovedRes.removedPackage = childPkg.packageName; childRemovedRes.isUpdate = false; childRemovedRes.dataRemoved = true; @@ -16870,7 +16870,7 @@ public class PackageManagerService extends IPackageManager.Stub { sUserManager.getUserIds(), true); } if ((mPackages.containsKey(childPkg.packageName))) { - childRes.removedInfo = new PackageRemovedInfo(); + childRes.removedInfo = new PackageRemovedInfo(this); childRes.removedInfo.removedPackage = childPkg.packageName; } if (res.addedChildPackages == null) { @@ -17716,7 +17716,7 @@ public class PackageManagerService extends IPackageManager.Stub { * sending a broadcast if necessary */ private int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) { - final PackageRemovedInfo info = new PackageRemovedInfo(); + final PackageRemovedInfo info = new PackageRemovedInfo(this); final boolean res; final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0 @@ -17816,7 +17816,8 @@ public class PackageManagerService extends IPackageManager.Stub { return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } - class PackageRemovedInfo { + static class PackageRemovedInfo { + final PackageSender packageSender; String removedPackage; int uid = -1; int removedAppId = -1; @@ -17834,6 +17835,10 @@ public class PackageManagerService extends IPackageManager.Stub { ArrayMap<String, PackageRemovedInfo> removedChildPackages; ArrayMap<String, PackageInstalledInfo> appearedChildPackages; + PackageRemovedInfo(PackageSender packageSender) { + this.packageSender = packageSender; + } + void sendPackageRemovedBroadcasts(boolean killApp) { sendPackageRemovedBroadcastInternal(killApp); final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0; @@ -17862,8 +17867,9 @@ public class PackageManagerService extends IPackageManager.Stub { ? appearedChildPackages.size() : 0; for (int i = 0; i < packageCount; i++) { PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i); - sendPackageAddedForNewUsers(installedInfo.name, true, - UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers); + packageSender.sendPackageAddedForNewUsers(installedInfo.name, + true, UserHandle.getAppId(installedInfo.uid), + installedInfo.newUsers); } } @@ -17871,12 +17877,12 @@ public class PackageManagerService extends IPackageManager.Stub { Bundle extras = new Bundle(2); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, - extras, 0, null, null, null); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, - extras, 0, null, null, null); - sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, - null, 0, removedPackage, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, + removedPackage, extras, 0, null, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, + removedPackage, extras, 0, null, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, + null, null, 0, removedPackage, null, null); } private void sendPackageRemovedBroadcastInternal(boolean killApp) { @@ -17895,19 +17901,37 @@ public class PackageManagerService extends IPackageManager.Stub { } extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, 0, null, null, broadcastUsers); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, + removedPackage, extras, 0, null, null, broadcastUsers); if (dataRemoved && !isRemovedPackageSystemUpdate) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, - removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, - null, null, broadcastUsers); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, + removedPackage, extras, + Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, + null, null, broadcastUsers); } } if (removedAppId >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, + packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers); } } + + void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) { + removedUsers = userIds; + if (removedUsers == null) { + broadcastUsers = null; + return; + } + + broadcastUsers = EMPTY_INT_ARRAY; + for (int i = userIds.length - 1; i >= 0; --i) { + final int userId = userIds[i]; + if (deletedPackageSetting.getInstantApp(userId)) { + continue; + } + broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId); + } + } } /* @@ -17931,23 +17955,8 @@ public class PackageManagerService extends IPackageManager.Stub { outInfo.removedPackage = packageName; outInfo.isStaticSharedLib = deletedPkg != null && deletedPkg.staticSharedLibName != null; - outInfo.removedUsers = deletedPs != null - ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true) - : null; - if (outInfo.removedUsers == null) { - outInfo.broadcastUsers = null; - } else { - outInfo.broadcastUsers = EMPTY_INT_ARRAY; - int[] allUsers = outInfo.removedUsers; - for (int i = allUsers.length - 1; i >= 0; --i) { - final int userId = allUsers[i]; - if (deletedPs.getInstantApp(userId)) { - continue; - } - outInfo.broadcastUsers = - ArrayUtils.appendInt(outInfo.broadcastUsers, userId); - } - } + outInfo.populateUsers(deletedPs == null ? null + : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs); } } @@ -18430,7 +18439,7 @@ public class PackageManagerService extends IPackageManager.Stub { outInfo.removedChildPackages = new ArrayMap<>(childCount); for (int i = 0; i < childCount; i++) { String childPackageName = ps.childPackageNames.get(i); - PackageRemovedInfo childInfo = new PackageRemovedInfo(); + PackageRemovedInfo childInfo = new PackageRemovedInfo(this); childInfo.removedPackage = childPackageName; outInfo.removedChildPackages.put(childPackageName, childInfo); PackageSetting childPs = mSettings.getPackageLPr(childPackageName); @@ -21692,7 +21701,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName); // Delete package internally - PackageRemovedInfo outInfo = new PackageRemovedInfo(); + PackageRemovedInfo outInfo = new PackageRemovedInfo(this); synchronized (mInstallLock) { final int deleteFlags = PackageManager.DELETE_KEEP_DATA; final boolean res; @@ -21859,7 +21868,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final ApplicationInfo info = ps.pkg.applicationInfo; final int deleteFlags = PackageManager.DELETE_KEEP_DATA; - final PackageRemovedInfo outInfo = new PackageRemovedInfo(); + final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, "unloadPrivatePackagesInner")) { @@ -23643,3 +23652,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); ? null : mInstantAppInstallerActivity.getComponentName(); } } + +interface PackageSender { + void sendPackageBroadcast(final String action, final String pkg, + final Bundle extras, final int flags, final String targetPkg, + final IIntentReceiver finishedReceiver, final int[] userIds); + void sendPackageAddedForNewUsers(String packageName, boolean isSystem, + int appId, int... userIds); +} diff --git a/services/core/java/com/android/server/storage/AppCollector.java b/services/core/java/com/android/server/storage/AppCollector.java index a77d33f8514b..03b754f777b3 100644 --- a/services/core/java/com/android/server/storage/AppCollector.java +++ b/services/core/java/com/android/server/storage/AppCollector.java @@ -21,22 +21,21 @@ import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageStats; import android.content.pm.UserInfo; import android.os.Handler; -import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.Process; -import android.os.RemoteException; import android.os.UserManager; import android.os.storage.VolumeInfo; import android.util.Log; + import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -44,7 +43,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; /** * AppCollector asynchronously collects package sizes. @@ -132,7 +130,7 @@ public class AppCollector { try { StorageStats storageStats = - mStorageStatsManager.queryStatsForPackage(app.volumeUuid, + mStorageStatsManager.queryStatsForPackage(app.storageUuid, app.packageName, user.getUserHandle()); PackageStats packageStats = new PackageStats(app.packageName, user.id); @@ -140,7 +138,7 @@ public class AppCollector { packageStats.codeSize = storageStats.getCodeBytes(); packageStats.dataSize = storageStats.getDataBytes(); stats.add(packageStats); - } catch (IllegalStateException e) { + } catch (NameNotFoundException | IOException e) { Log.e(TAG, "An exception occurred while fetching app size", e); } } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index f41eed53cbca..e6345523bd14 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.Animator; import android.animation.ValueAnimator; +import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.os.Handler; @@ -35,6 +36,9 @@ import android.view.WindowManagerInternal; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Enables animating bounds of objects. * @@ -43,7 +47,7 @@ import com.android.internal.annotations.VisibleForTesting; * relaunching it would cause poorer experience), these class provides a way to directly animate * the bounds of the resized object. * - * The object that is resized needs to implement {@link AnimateBoundsUser} interface. + * The object that is resized needs to implement {@link BoundsAnimationTarget} interface. * * NOTE: All calls to methods in this class should be done on the UI thread */ @@ -56,8 +60,19 @@ public class BoundsAnimationController { private static final int DEFAULT_TRANSITION_DURATION = 425; + @Retention(RetentionPolicy.SOURCE) + @IntDef({NO_PIP_MODE_CHANGED_CALLBACKS, SCHEDULE_PIP_MODE_CHANGED_ON_START, + SCHEDULE_PIP_MODE_CHANGED_ON_END}) + public @interface SchedulePipModeChangedState {} + /** Do not schedule any PiP mode changed callbacks as a part of this animation. */ + public static final int NO_PIP_MODE_CHANGED_CALLBACKS = 0; + /** Schedule a PiP mode changed callback when this animation starts. */ + public static final int SCHEDULE_PIP_MODE_CHANGED_ON_START = 1; + /** Schedule a PiP mode changed callback when this animation ends. */ + public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2; + // Only accessed on UI thread. - private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); + private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); private final class AppTransitionNotifier extends WindowManagerInternal.AppTransitionListener implements Runnable { @@ -108,40 +123,42 @@ public class BoundsAnimationController { @VisibleForTesting final class BoundsAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { - private final AnimateBoundsUser mTarget; + private final BoundsAnimationTarget mTarget; private final Rect mFrom = new Rect(); private final Rect mTo = new Rect(); private final Rect mTmpRect = new Rect(); private final Rect mTmpTaskBounds = new Rect(); - private final boolean mMoveToFullScreen; - // True if this this animation was cancelled and will be replaced the another animation from - // the same {@link #AnimateBoundsUser} target. + + // True if this this animation was canceled and will be replaced the another animation from + // the same {@link #BoundsAnimationTarget} target. private boolean mSkipFinalResize; // True if this animation replaced a previous animation of the same - // {@link #AnimateBoundsUser} target. + // {@link #BoundsAnimationTarget} target. private final boolean mSkipAnimationStart; - // True if this animation was cancelled by the user, not as a part of a replacing animation + // True if this animation was canceled by the user, not as a part of a replacing animation private boolean mSkipAnimationEnd; - // True if this animation is not replacing a previous animation, or if the previous - // animation is animating to a different fullscreen state than the current animation. - // We use this to ensure that we always provide a consistent set/order of callbacks when we - // transition to/from PiP. - private final boolean mAnimatingToNewFullscreenState; + // True if the animation target should be moved to the fullscreen stack at the end of this + // animation + private boolean mMoveToFullscreen; + + // Whether to schedule PiP mode changes on animation start/end + private @SchedulePipModeChangedState int mSchedulePipModeChangedState; // Depending on whether we are animating from // a smaller to a larger size private final int mFrozenTaskWidth; private final int mFrozenTaskHeight; - BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, boolean moveToFullScreen, - boolean replacingExistingAnimation, boolean animatingToNewFullscreenState) { + BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to, + @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen, boolean replacingExistingAnimation) { super(); mTarget = target; mFrom.set(from); mTo.set(to); - mMoveToFullScreen = moveToFullScreen; mSkipAnimationStart = replacingExistingAnimation; - mAnimatingToNewFullscreenState = animatingToNewFullscreenState; + mSchedulePipModeChangedState = schedulePipModeChangedState; + mMoveToFullscreen = moveToFullscreen; addUpdateListener(this); addListener(this); @@ -161,7 +178,8 @@ public class BoundsAnimationController { @Override public void onAnimationStart(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget - + " mSkipAnimationStart=" + mSkipAnimationStart); + + " mSkipAnimationStart=" + mSkipAnimationStart + + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState); mFinishAnimationAfterTransition = false; mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight); @@ -170,13 +188,8 @@ public class BoundsAnimationController { // we trigger any size changes, so it can swap surfaces // in to appropriate modes, or do as it wishes otherwise. if (!mSkipAnimationStart) { - mTarget.onAnimationStart(mMoveToFullScreen); - } - - // If we are animating to a new fullscreen state (either to/from fullscreen), then - // notify the target of the change with the new frozen task bounds - if (mAnimatingToNewFullscreenState && mMoveToFullScreen) { - mTarget.updatePictureInPictureMode(null); + mTarget.onAnimationStart(mSchedulePipModeChangedState == + SCHEDULE_PIP_MODE_CHANGED_ON_START); } // Immediately update the task bounds if they have to become larger, but preserve @@ -206,20 +219,26 @@ public class BoundsAnimationController { // any further animation. if (DEBUG) Slog.d(TAG, "animateUpdate: cancelled"); + // If we have already scheduled a PiP mode changed at the start of the animation, + // then we need to clean up and schedule one at the end, since we have canceled the + // animation to the final state. + if (mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + mSchedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + // Since we are cancelling immediately without a replacement animation, send the // animation end to maintain callback parity, but also skip any further resizes - prepareCancel(false /* skipAnimationEnd */, true /* skipFinalResize */); - cancel(); + cancelAndCallAnimationEnd(); } } @Override public void onAnimationEnd(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget - + " mMoveToFullScreen=" + mMoveToFullScreen + " mSkipFinalResize=" + mSkipFinalResize + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition - + " mAppTransitionIsRunning=" + mAppTransition.isRunning()); + + " mAppTransitionIsRunning=" + mAppTransition.isRunning() + + " callers=" + Debug.getCallers(2)); // There could be another animation running. For example in the // move to fullscreen case, recents will also be closing while the @@ -231,58 +250,57 @@ public class BoundsAnimationController { return; } - if (!mSkipFinalResize) { - // If not cancelled, resize the pinned stack to the final size. All calls to - // setPinnedStackSize() must be done between onAnimationStart() and onAnimationEnd() - mTarget.setPinnedStackSize(mTo, null); + if (!mSkipAnimationEnd) { + // If this animation has already scheduled the picture-in-picture mode on start, and + // we are not skipping the final resize due to being canceled, then move the PiP to + // fullscreen once the animation ends + if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget + + " moveToFullscreen=" + mMoveToFullscreen); + mTarget.onAnimationEnd(mSchedulePipModeChangedState == + SCHEDULE_PIP_MODE_CHANGED_ON_END, !mSkipFinalResize ? mTo : null, + mMoveToFullscreen); } - finishAnimation(); - - if (mMoveToFullScreen && !mSkipFinalResize) { - mTarget.moveToFullscreen(); - } + // Clean up this animation + removeListener(this); + removeUpdateListener(this); + mRunningAnimations.remove(mTarget); } @Override public void onAnimationCancel(Animator animation) { - finishAnimation(); + // Always skip the final resize when the animation is canceled + mSkipFinalResize = true; + mMoveToFullscreen = false; } - public void prepareCancel(boolean skipAnimationEnd, boolean skipFinalResize) { - if (DEBUG) Slog.d(TAG, "prepareCancel: skipAnimationEnd=" + skipAnimationEnd - + " skipFinalResize=" + skipFinalResize); - mSkipAnimationEnd = skipAnimationEnd; - mSkipFinalResize = skipFinalResize; + private void cancelAndCallAnimationEnd() { + if (DEBUG) Slog.d(TAG, "cancelAndCallAnimationEnd: mTarget=" + mTarget); + mSkipAnimationEnd = false; + super.cancel(); } @Override public void cancel() { if (DEBUG) Slog.d(TAG, "cancel: mTarget=" + mTarget); + mSkipAnimationEnd = true; super.cancel(); } - /** Returns true if the animation target is the same as the input bounds. */ + /** + * @return true if the animation target is the same as the input bounds. + */ boolean isAnimatingTo(Rect bounds) { return mTo.equals(bounds); } - private boolean animatingToLargerSize() { - if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) { - return false; - } - return true; - } - - private void finishAnimation() { - if (DEBUG) Slog.d(TAG, "finishAnimation: mTarget=" + mTarget - + " callers" + Debug.getCallers(2)); - if (!mSkipAnimationEnd) { - mTarget.onAnimationEnd(); - } - removeListener(this); - removeUpdateListener(this); - mRunningAnimations.remove(mTarget); + /** + * @return true if we are animating to a larger surface size + */ + @VisibleForTesting + boolean animatingToLargerSize() { + // TODO: Fix this check for aspect ratio changes + return (mFrom.width() * mFrom.height() <= mTo.width() * mTo.height()); } @Override @@ -291,63 +309,23 @@ public class BoundsAnimationController { } } - public interface AnimateBoundsUser { - /** - * Sets the size of the target (without any intermediate steps, like scheduling animation) - * but freezes the bounds of any tasks in the target at taskBounds, - * to allow for more flexibility during resizing. Only works for the pinned stack at the - * moment. - * - * @return Whether the target should continue to be animated and this call was successful. - * If false, the animation will be cancelled because the user has determined that the - * animation is now invalid and not required. In such a case, the cancel will trigger the - * animation end callback as well, but will not send any further size changes. - */ - boolean setPinnedStackSize(Rect bounds, Rect taskBounds); - - /** - * Callback for the target to inform it that the animation has started, so it can do some - * necessary preparation. - */ - void onAnimationStart(boolean toFullscreen); - - /** - * Callback for the target to inform it that the animation is going to a new fullscreen - * state and should update the picture-in-picture mode accordingly. - * - * @param targetStackBounds the target stack bounds we are animating to, can be null if - * we are animating to fullscreen - */ - void updatePictureInPictureMode(Rect targetStackBounds); - - /** - * Callback for the target to inform it that the animation has ended, so it can do some - * necessary cleanup. - */ - void onAnimationEnd(); - - /** - * Callback for the target to inform it to reparent to the fullscreen stack. - */ - void moveToFullscreen(); - } - - public void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, - int animationDuration, boolean moveToFullscreen) { - animateBoundsImpl(target, from, to, animationDuration, moveToFullscreen); + public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to, + int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen) { + animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState, + moveToFullscreen); } @VisibleForTesting - BoundsAnimator animateBoundsImpl(final AnimateBoundsUser target, Rect from, Rect to, - int animationDuration, boolean moveToFullscreen) { + BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to, + int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen) { final BoundsAnimator existing = mRunningAnimations.get(target); final boolean replacing = existing != null; - final boolean animatingToNewFullscreenState = (existing == null) || - (existing.mMoveToFullScreen != moveToFullscreen); if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to - + " moveToFullscreen=" + moveToFullscreen + " replacing=" + replacing - + " animatingToNewFullscreenState=" + animatingToNewFullscreenState); + + " schedulePipModeChangedState=" + schedulePipModeChangedState + + " replacing=" + replacing); if (replacing) { if (existing.isAnimatingTo(to)) { @@ -355,15 +333,36 @@ public class BoundsAnimationController { // one we are trying to start. if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing + " ignoring..."); + return existing; } - // Since we are replacing, we skip both animation start and end callbacks, and don't - // animate to the final bounds when cancelling - existing.prepareCancel(true /* skipAnimationEnd */, true /* skipFinalResize */); + + // Update the PiP callback states if we are replacing the animation + if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (DEBUG) Slog.d(TAG, "animateBounds: still animating to fullscreen, keep" + + " existing deferred state"); + } else { + if (DEBUG) Slog.d(TAG, "animateBounds: fullscreen animation canceled, callback" + + " on start already processed, schedule deferred update on end"); + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + } else if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END) { + if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (DEBUG) Slog.d(TAG, "animateBounds: non-fullscreen animation canceled," + + " callback on start will be processed"); + } else { + if (DEBUG) Slog.d(TAG, "animateBounds: still animating from fullscreen, keep" + + " existing deferred state"); + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + } + + // Since we are replacing, we skip both animation start and end callbacks existing.cancel(); } - final BoundsAnimator animator = new BoundsAnimator(target, from, to, moveToFullscreen, - replacing, animatingToNewFullscreenState); + final BoundsAnimator animator = new BoundsAnimator(target, from, to, + schedulePipModeChangedState, moveToFullscreen, replacing); mRunningAnimations.put(target, animator); animator.setFloatValues(0f, 1f); animator.setDuration((animationDuration != -1 ? animationDuration diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java new file mode 100644 index 000000000000..8b1bf7bf77dc --- /dev/null +++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java @@ -0,0 +1,62 @@ +/* + * 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 distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import android.graphics.Rect; + +/** + * The target for a BoundsAnimation. + * @see BoundsAnimationController + */ +interface BoundsAnimationTarget { + + /** + * Callback for the target to inform it that the animation has started, so it can do some + * necessary preparation. + * + * @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed + * callbacks + */ + void onAnimationStart(boolean schedulePipModeChangedCallback); + + /** + * Sets the size of the target (without any intermediate steps, like scheduling animation) + * but freezes the bounds of any tasks in the target at taskBounds, to allow for more + * flexibility during resizing. Only works for the pinned stack at the moment. This will + * only be called between onAnimationStart() and onAnimationEnd(). + * + * @return Whether the target should continue to be animated and this call was successful. + * If false, the animation will be cancelled because the user has determined that the + * animation is now invalid and not required. In such a case, the cancel will trigger the + * animation end callback as well, but will not send any further size changes. + */ + boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds); + + /** + * Callback for the target to inform it that the animation has ended, so it can do some + * necessary cleanup. + * + * @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed + * callbacks + * @param finalStackSize the final stack bounds to set on the target (can be to indicate that + * the animation was cancelled and the target does not need to update to the final stack bounds) + * @param moveToFullscreen whether or the target should reparent itself to the fullscreen stack + * when the animation completes + */ + void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, + boolean moveToFullscreen); +} diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 16848780fe47..82416ec513c4 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -26,7 +26,6 @@ import android.app.RemoteAction; import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -123,6 +122,13 @@ class PinnedStackController { mSnapAlgorithm.setMinimized(isMinimized); }); } + + @Override + public int getDisplayRotation() { + synchronized (mService.mWindowMap) { + return mDisplayInfo.rotation; + } + } } /** @@ -221,22 +227,26 @@ class PinnedStackController { * @return the size of the PIP based on the given {@param aspectRatio}. */ Size getSize(float aspectRatio) { - return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize, - mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + synchronized (mService.mWindowMap) { + return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize, + mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + } } /** * @return the default bounds to show the PIP when there is no active PIP. */ Rect getDefaultBounds() { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - - final Rect defaultBounds = new Rect(); - final Size size = getSize(mDefaultAspectRatio); - Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds, - 0, mIsImeShowing ? mImeHeight : 0, defaultBounds); - return defaultBounds; + synchronized (mService.mWindowMap) { + final Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + + final Rect defaultBounds = new Rect(); + final Size size = getSize(mDefaultAspectRatio); + Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds, + 0, mIsImeShowing ? mImeHeight : 0, defaultBounds); + return defaultBounds; + } } /** @@ -254,42 +264,44 @@ class PinnedStackController { * new orientation of the device if necessary. */ boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) { - final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); - if (mDisplayInfo.equals(displayInfo)) { - // We are already in the right orientation, ignore - outBounds.setEmpty(); - return false; - } else if (targetBounds.isEmpty()) { - // The stack is null, we are just initializing the stack, so just store the display info - // and ignore + synchronized (mService.mWindowMap) { + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + if (mDisplayInfo.equals(displayInfo)) { + // We are already in the right orientation, ignore + outBounds.setEmpty(); + return false; + } else if (targetBounds.isEmpty()) { + // The stack is null, we are just initializing the stack, so just store the display + // info and ignore + mDisplayInfo.copyFrom(displayInfo); + outBounds.setEmpty(); + return false; + } + + mTmpRect.set(targetBounds); + final Rect postChangeStackBounds = mTmpRect; + + // Calculate the snap fraction of the current stack along the old movement bounds + final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds); + final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds, + preChangeMovementBounds); mDisplayInfo.copyFrom(displayInfo); - outBounds.setEmpty(); - return false; - } - mTmpRect.set(targetBounds); - final Rect postChangeStackBounds = mTmpRect; - - // Calculate the snap fraction of the current stack along the old movement bounds - final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds); - final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds, - preChangeMovementBounds); - mDisplayInfo.copyFrom(displayInfo); - - // Calculate the stack bounds in the new orientation to the same same fraction along the - // rotated movement bounds. - final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds, - false /* adjustForIme */); - mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, - snapFraction); - if (mIsMinimized) { - applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds); - } + // Calculate the stack bounds in the new orientation to the same same fraction along the + // rotated movement bounds. + final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds, + false /* adjustForIme */); + mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, + snapFraction); + if (mIsMinimized) { + applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds); + } - notifyMovementBoundsChanged(false /* fromImeAdjustment */); + notifyMovementBoundsChanged(false /* fromImeAdjustment */); - outBounds.set(postChangeStackBounds); - return true; + outBounds.set(postChangeStackBounds); + return true; + } } /** @@ -378,25 +390,27 @@ class PinnedStackController { * Notifies listeners that the PIP movement bounds have changed. */ private void notifyMovementBoundsChanged(boolean fromImeAdjustement) { - if (mPinnedStackListener != null) { - try { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - final Rect normalBounds = getDefaultBounds(); - if (isValidPictureInPictureAspectRatio(mAspectRatio)) { - transformBoundsToAspectRatio(normalBounds, mAspectRatio); - } - final Rect animatingBounds = mTmpAnimatingBoundsRect; - final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID); - if (pinnedStack != null) { - pinnedStack.getAnimationOrCurrentBounds(animatingBounds); - } else { - animatingBounds.set(normalBounds); + synchronized (mService.mWindowMap) { + if (mPinnedStackListener != null) { + try { + final Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + final Rect normalBounds = getDefaultBounds(); + if (isValidPictureInPictureAspectRatio(mAspectRatio)) { + transformBoundsToAspectRatio(normalBounds, mAspectRatio); + } + final Rect animatingBounds = mTmpAnimatingBoundsRect; + final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID); + if (pinnedStack != null) { + pinnedStack.getAnimationOrCurrentBounds(animatingBounds); + } else { + animatingBounds.set(normalBounds); + } + mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds, + animatingBounds, fromImeAdjustement, mDisplayInfo.rotation); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering actions changed event.", e); } - mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds, - animatingBounds, fromImeAdjustement); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering actions changed event.", e); } } } @@ -405,11 +419,13 @@ class PinnedStackController { * @return the bounds on the screen that the PIP can be visible in. */ private void getInsetBounds(Rect outRect) { - mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, - mDisplayInfo.logicalHeight, mTmpInsets); - outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, - mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, - mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); + synchronized (mService.mWindowMap) { + mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, + mDisplayInfo.logicalHeight, mTmpInsets); + outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, + mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, + mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); + } } /** @@ -417,7 +433,9 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds) { - return getMovementBounds(stackBounds, true /* adjustForIme */); + synchronized (mService.mWindowMap) { + return getMovementBounds(stackBounds, true /* adjustForIme */); + } } /** @@ -425,23 +443,27 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) { - final Rect movementBounds = new Rect(); - getInsetBounds(movementBounds); - - // Apply the movement bounds adjustments based on the current state - mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds, - (adjustForIme && mIsImeShowing) ? mImeHeight : 0); - return movementBounds; + synchronized (mService.mWindowMap) { + final Rect movementBounds = new Rect(); + getInsetBounds(movementBounds); + + // Apply the movement bounds adjustments based on the current state + mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds, + (adjustForIme && mIsImeShowing) ? mImeHeight : 0); + return movementBounds; + } } /** * Applies the minimized offsets to the given stack bounds. */ private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) { - mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); - mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets); - mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize, - mStableInsets); + synchronized (mService.mWindowMap) { + mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets); + mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize, + mStableInsets); + } } /** diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java index 135832e619a4..5b9c16ce60c9 100644 --- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java +++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java @@ -17,6 +17,10 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; +import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState; import android.app.RemoteAction; import android.graphics.Rect; @@ -40,36 +44,53 @@ public class PinnedStackWindowController extends StackWindowController { /** * Animates the pinned stack. */ - public void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, - int animationDuration) { + public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, + int animationDuration, boolean schedulePipModeChangedOnAnimationEnd) { synchronized (mWindowMap) { if (mContainer == null) { throw new IllegalArgumentException("Pinned stack container not found :("); } - // Get non-null fullscreen bounds if the bounds are null - final boolean moveToFullscreen = destBounds == null; - destBounds = getPinnedStackAnimationBounds(destBounds); - - // If the bounds are truly null, then there was no fullscreen stack at this time, so - // animate this to the full display bounds - final Rect toBounds; - if (destBounds == null) { - toBounds = new Rect(); - mContainer.getDisplayContent().getLogicalDisplayRect(toBounds); - } else { - toBounds = destBounds; + // Get the from-bounds + final Rect fromBounds = new Rect(); + mContainer.getBounds(fromBounds); + + // Get non-null fullscreen to-bounds for animating if the bounds are null + @SchedulePipModeChangedState int schedulePipModeChangedState = + NO_PIP_MODE_CHANGED_CALLBACKS; + final boolean toFullscreen = toBounds == null; + if (toFullscreen) { + if (schedulePipModeChangedOnAnimationEnd) { + throw new IllegalArgumentException("Should not defer scheduling PiP mode" + + " change on animation to fullscreen."); + } + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START; + + mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect); + if (!mTmpBoundsRect.isEmpty()) { + // If there is a fullscreen bounds, use that + toBounds = new Rect(mTmpBoundsRect); + } else { + // Otherwise, use the display bounds + toBounds = new Rect(); + mContainer.getDisplayContent().getLogicalDisplayRect(toBounds); + } + } else if (schedulePipModeChangedOnAnimationEnd) { + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; } - final Rect originalBounds = new Rect(); - mContainer.getBounds(originalBounds); - mContainer.setAnimationFinalBounds(sourceBounds, toBounds); + mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen); + + final Rect finalToBounds = toBounds; + final @SchedulePipModeChangedState int finalSchedulePipModeChangedState = + schedulePipModeChangedState; UiThread.getHandler().post(() -> { if (mContainer == null) { return; } - mService.mBoundsAnimationController.animateBounds(mContainer, originalBounds, - toBounds, animationDuration, moveToFullscreen); + mService.mBoundsAnimationController.animateBounds(mContainer, fromBounds, + finalToBounds, animationDuration, finalSchedulePipModeChangedState, + toFullscreen); }); } } @@ -93,7 +114,8 @@ public class PinnedStackWindowController extends StackWindowController { if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) { if (!toBounds.equals(targetBounds)) { - animateResizePinnedStack(null /* sourceBounds */, toBounds, -1 /* duration */); + animateResizePinnedStack(toBounds, null /* sourceHintBounds */, + -1 /* duration */, false /* schedulePipModeChangedOnAnimationEnd */); } pinnedStackController.setAspectRatio( pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio) @@ -116,26 +138,31 @@ public class PinnedStackWindowController extends StackWindowController { } /** - * @return whether the bounds are currently animating to fullscreen. + * @return whether the multi-window mode change should be deferred as a part of a transition + * from fullscreen to non-fullscreen bounds. */ - public boolean isAnimatingBoundsToFullscreen() { - return mContainer.isAnimatingBoundsToFullscreen(); + public boolean deferScheduleMultiWindowModeChanged() { + synchronized(mWindowMap) { + return mContainer.deferScheduleMultiWindowModeChanged(); + } } - public boolean pinnedStackResizeAllowed() { - return mContainer.pinnedStackResizeAllowed(); + /** + * @return whether the bounds are currently animating to fullscreen. + */ + public boolean isAnimatingBoundsToFullscreen() { + synchronized (mWindowMap) { + return mContainer.isAnimatingBoundsToFullscreen(); + } } /** - * Checks the {@param bounds} and retirms non-null fullscreen bounds for the pinned stack - * animation if necessary. + * @return whether the stack can be resized from the bounds animation. */ - private Rect getPinnedStackAnimationBounds(Rect bounds) { - mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect); - if (bounds == null && !mTmpBoundsRect.isEmpty()) { - bounds = new Rect(mTmpBoundsRect); + public boolean pinnedStackResizeDisallowed() { + synchronized (mWindowMap) { + return mContainer.pinnedStackResizeDisallowed(); } - return bounds; } /** diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index d7c41d335b72..d141f7cb2eb3 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -56,7 +56,7 @@ import com.android.server.EventLogTags; import java.io.PrintWriter; public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLayerUser, - BoundsAnimationController.AnimateBoundsUser { + BoundsAnimationTarget { /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to * restrict IME adjustment so that a min portion of top stack remains visible.*/ private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; @@ -132,7 +132,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye private boolean mBoundsAnimatingToFullscreen = false; private boolean mCancelCurrentBoundsAnimation = false; private Rect mBoundsAnimationTarget = new Rect(); - private Rect mBoundsAnimationSourceBounds = new Rect(); + private Rect mBoundsAnimationSourceHintBounds = new Rect(); // Temporary storage for the new bounds that should be used after the configuration change. // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). @@ -322,18 +322,19 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye * Sets the bounds animation target bounds ahead of an animation. This can't currently be done * in onAnimationStart() since that is started on the UiThread. */ - void setAnimationFinalBounds(Rect sourceBounds, Rect destBounds) { + void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) { mBoundsAnimatingRequested = true; - if (sourceBounds != null) { - mBoundsAnimationSourceBounds.set(sourceBounds); - } else { - mBoundsAnimationSourceBounds.setEmpty(); - } + mBoundsAnimatingToFullscreen = toFullscreen; if (destBounds != null) { mBoundsAnimationTarget.set(destBounds); } else { mBoundsAnimationTarget.setEmpty(); } + if (sourceHintBounds != null) { + mBoundsAnimationSourceHintBounds.set(sourceHintBounds); + } else { + mBoundsAnimationSourceHintBounds.setEmpty(); + } } /** @@ -346,8 +347,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye /** * @return the final source bounds for the bounds animation. */ - void getFinalAnimationSourceBounds(Rect outBounds) { - outBounds.set(mBoundsAnimationSourceBounds); + void getFinalAnimationSourceHintBounds(Rect outBounds) { + outBounds.set(mBoundsAnimationSourceHintBounds); } /** @@ -413,7 +414,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye // orientation, clear the animation target bounds since they are obsolete, and // cancel any currently running animations mBoundsAnimationTarget.setEmpty(); - mBoundsAnimationSourceBounds.setEmpty(); + mBoundsAnimationSourceHintBounds.setEmpty(); mCancelCurrentBoundsAnimation = true; return true; } @@ -1458,13 +1459,16 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } } - public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) { - if (mCancelCurrentBoundsAnimation) { - return false; + public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread + synchronized (mService.mWindowMap) { + if (mCancelCurrentBoundsAnimation) { + return false; + } } try { - mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds); + mService.mActivityManager.resizePinnedStack(stackBounds, tempTaskBounds); } catch (RemoteException e) { // I don't believe you. } @@ -1472,11 +1476,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } @Override // AnimatesBounds - public void onAnimationStart(boolean toFullscreen) { + public void onAnimationStart(boolean schedulePipModeChangedCallback) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { mBoundsAnimatingRequested = false; mBoundsAnimating = true; - mBoundsAnimatingToFullscreen = toFullscreen; mCancelCurrentBoundsAnimation = false; } @@ -1486,41 +1490,63 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } catch (RemoteException e) { // I don't believe you... } - } - } - @Override // AnimatesBounds - public void updatePictureInPictureMode(Rect targetStackBounds) { - final PinnedStackWindowController controller = - (PinnedStackWindowController) getController(); - if (controller != null) { - controller.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds); + final PinnedStackWindowController controller = + (PinnedStackWindowController) getController(); + if (schedulePipModeChangedCallback && controller != null) { + // We need to schedule the PiP mode change after the animation down, so use the + // final bounds + controller.updatePictureInPictureModeForPinnedStackAnimation(null); + } } } @Override // AnimatesBounds - public void onAnimationEnd() { + public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, + boolean moveToFullscreen) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { mBoundsAnimating = false; mService.requestTraversal(); } if (mStackId == PINNED_STACK_ID) { + final PinnedStackWindowController controller = + (PinnedStackWindowController) getController(); + if (schedulePipModeChangedCallback && controller != null) { + // We need to schedule the PiP mode change after the animation down, so use the + // final bounds + controller.updatePictureInPictureModeForPinnedStackAnimation( + mBoundsAnimationTarget); + } + + // Update to the final bounds if requested. This is done here instead of in the bounds + // animator to allow us to coordinate this after we notify the PiP mode changed + if (finalStackSize != null) { + setPinnedStackSize(finalStackSize, null); + } + try { mService.mActivityManager.notifyPinnedStackAnimationEnded(); + if (moveToFullscreen) { + mService.mActivityManager.moveTasksToFullscreenStack(mStackId, + true /* onTop */); + } } catch (RemoteException e) { // I don't believe you... } } } - @Override - public void moveToFullscreen() { - try { - mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true); - } catch (RemoteException e) { - e.printStackTrace(); + /** + * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen + * bounds and we have a deferred PiP mode changed callback set with the animation. + */ + public boolean deferScheduleMultiWindowModeChanged() { + if (mStackId == PINNED_STACK_ID) { + return (mBoundsAnimatingRequested || mBoundsAnimating); } + return false; } public boolean hasMovementAnimations() { @@ -1539,7 +1565,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye return mBoundsAnimating && mBoundsAnimatingToFullscreen; } - public boolean pinnedStackResizeAllowed() { + public boolean pinnedStackResizeDisallowed() { if (mBoundsAnimating && mCancelCurrentBoundsAnimation) { return true; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0b96f3fbc1fc..9555c8dff03c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4365,9 +4365,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // When we change the Surface size, in scenarios which may require changing // the surface position in sync with the resize, we use a preserved surface // so we can freeze it while waiting for the client to report draw on the newly - // sized surface. + // sized surface. Don't preserve surfaces if the insets change while animating the pinned + // stack since it can lead to issues if a new surface is created while calculating the + // scale for the animation using the source hint rect + // (see WindowStateAnimator#setSurfaceBoundariesLocked()). if (isDragResizeChanged() || isResizedWhileNotDragResizing() - || surfaceInsetsChanging()) { + || (surfaceInsetsChanging() && !inPinnedWorkspace())) { mLastSurfaceInsets.set(mAttrs.surfaceInsets); setDragResizing(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index fa353367c6e4..a2889b145f16 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1360,7 +1360,7 @@ class WindowStateAnimator { int posX = mTmpSize.left; int posY = mTmpSize.top; task.mStack.getDimBounds(mTmpStackBounds); - task.mStack.getFinalAnimationSourceBounds(mTmpSourceBounds); + task.mStack.getFinalAnimationSourceHintBounds(mTmpSourceBounds); if (!mTmpSourceBounds.isEmpty()) { // Get the final target stack bounds, if we are not animating, this is just the // current stack bounds diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index f666727ec1d1..57ee928f7682 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -49,6 +49,7 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.graphics.Color; import android.os.Binder; +import android.os.Process; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -460,10 +461,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(channel2), + eq(Process.myUserHandle()), eq(channel2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -481,10 +482,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannelGroups(PKG, new ParceledListSlice(Arrays.asList(group1, group2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group1), + eq(Process.myUserHandle()), eq(group1), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group2), + eq(Process.myUserHandle()), eq(group2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -503,7 +504,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -520,7 +521,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -537,7 +538,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(ncg), + eq(Process.myUserHandle()), eq(ncg), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -550,12 +551,12 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -568,7 +569,7 @@ public class NotificationManagerServiceTest { try { mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -577,7 +578,33 @@ public class NotificationManagerServiceTest { verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), + eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); + } + + @Test + @UiThreadTest + public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.updateNotificationChannelFromPrivilegedListener( + null, PKG, UserHandle.ALL, mTestNotificationChannel); + fail("incorrectly allowed a change to a user listener cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); + + verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -589,7 +616,8 @@ public class NotificationManagerServiceTest { associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannels( anyString(), anyInt(), anyBoolean()); @@ -603,7 +631,8 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -615,13 +644,37 @@ public class NotificationManagerServiceTest { @Test @UiThreadTest + public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listener getting channels from a user they cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test + @UiThreadTest public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt()); } @@ -634,7 +687,29 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listeners that don't have a companion device shouldn't be able to call this"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); + } + + @Test + @UiThreadTest + public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java new file mode 100644 index 000000000000..243c1b379608 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java @@ -0,0 +1,76 @@ +/* + * 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 distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.content.Context; +import android.os.Handler; +import android.support.test.InstrumentationRegistry; +import android.support.test.annotation.UiThreadTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.AppOpsService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +/** + * runtest -c com.android.server.am.AppErrorDialogTest frameworks-services + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AppErrorDialogTest { + + private Context mContext; + private ActivityManagerService mService; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + mService = new ActivityManagerService(new ActivityManagerService.Injector() { + @Override + public AppOpsService getAppOpsService(File file, Handler handler) { + return null; + } + + @Override + public Handler getUiHandler(ActivityManagerService service) { + return null; + } + + @Override + public boolean isNetworkRestrictedForUid(int uid) { + return false; + } + }); + } + + @Test + @UiThreadTest + public void testCreateWorks() throws Exception { + AppErrorDialog.Data data = new AppErrorDialog.Data(); + data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345); + data.result = new AppErrorResult(); + + AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data); + + dialog.create(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java new file mode 100644 index 000000000000..8f2f34ee77d9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -0,0 +1,89 @@ +/* + * 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 distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.content.IIntentReceiver; + +import android.os.Bundle; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.File; + +// runtest -c com.android.server.pm.PackageManagerServiceTest frameworks-services + +@SmallTest +public class PackageManagerServiceTest extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testPackageRemoval() throws Exception { + class PackageSenderImpl implements PackageSender { + public void sendPackageBroadcast(final String action, final String pkg, + final Bundle extras, final int flags, final String targetPkg, + final IIntentReceiver finishedReceiver, final int[] userIds) { + } + + public void sendPackageAddedForNewUsers(String packageName, + boolean isSystem, int appId, int... userIds) { + } + } + + PackageSenderImpl sender = new PackageSenderImpl(); + PackageSetting setting = null; + PackageManagerService.PackageRemovedInfo pri = + new PackageManagerService.PackageRemovedInfo(sender); + + // Initial conditions: nothing there + assertNull(pri.removedUsers); + assertNull(pri.broadcastUsers); + + // populateUsers with nothing leaves nothing + pri.populateUsers(null, setting); + assertNull(pri.broadcastUsers); + + // Create a real (non-null) PackageSetting and confirm that the removed + // users are copied properly + setting = new PackageSetting("name", "realName", new File("codePath"), + new File("resourcePath"), "legacyNativeLibraryPathString", + "primaryCpuAbiString", "secondaryCpuAbiString", + "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0, + null, null); + pri.populateUsers(new int[] {1, 2, 3, 4, 5}, setting); + assertNotNull(pri.broadcastUsers); + assertEquals(5, pri.broadcastUsers.length); + + // Exclude a user + pri.broadcastUsers = null; + final int EXCLUDED_USER_ID = 4; + setting.setInstantApp(true, EXCLUDED_USER_ID); + pri.populateUsers(new int[] {1, 2, 3, EXCLUDED_USER_ID, 5}, setting); + assertNotNull(pri.broadcastUsers); + assertEquals(5 - 1, pri.broadcastUsers.length); + + // TODO: test that sendApplicationHiddenForUser() actually fills in + // broadcastUsers + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index 85dc7125e3cc..7f150a21a20e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -16,6 +16,11 @@ package com.android.server.wm; +import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; +import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState; + import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; @@ -47,6 +52,12 @@ import com.android.server.wm.BoundsAnimationController.BoundsAnimator; * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks * depending on the various interactions. * + * We are really concerned about only three of the transition states [F = fullscreen, !F = floating] + * F->!F, !F->!F, and !F->F. Each animation can only be cancelled from the target mid-transition, + * or if a new animation starts on the same target. The tests below verifies that the target is + * notified of all the cases where it is animating and cancelled so that it can respond + * appropriately. + * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests */ @@ -109,47 +120,46 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * A test animate bounds user to track callbacks from the bounds animation. */ - private class TestAnimateBoundsUser implements BoundsAnimationController.AnimateBoundsUser { + private class TestBoundsAnimationTarget implements BoundsAnimationTarget { + boolean mAwaitingAnimationStart; boolean mMovedToFullscreen; boolean mAnimationStarted; - boolean mAnimationStartedToFullscreen; + boolean mSchedulePipModeChangedOnStart; boolean mAnimationEnded; - boolean mUpdatedPictureInPictureModeWithBounds; + Rect mAnimationEndFinalStackBounds; + boolean mSchedulePipModeChangedOnEnd; boolean mBoundsUpdated; + boolean mCancelRequested; Rect mStackBounds; Rect mTaskBounds; - boolean mRequestCancelAnimation = false; - - void reinitialize(Rect stackBounds, Rect taskBounds) { + void initialize(Rect from) { + mAwaitingAnimationStart = true; mMovedToFullscreen = false; mAnimationStarted = false; - mAnimationStartedToFullscreen = false; mAnimationEnded = false; - mUpdatedPictureInPictureModeWithBounds = false; - mStackBounds = stackBounds; - mTaskBounds = taskBounds; + mAnimationEndFinalStackBounds = null; + mSchedulePipModeChangedOnStart = false; + mSchedulePipModeChangedOnEnd = false; + mStackBounds = from; + mTaskBounds = null; mBoundsUpdated = false; - mRequestCancelAnimation = false; } @Override - public void onAnimationStart(boolean toFullscreen) { + public void onAnimationStart(boolean schedulePipModeChangedCallback) { + mAwaitingAnimationStart = false; mAnimationStarted = true; - mAnimationStartedToFullscreen = toFullscreen; - } - - @Override - public void updatePictureInPictureMode(Rect targetStackBounds) { - mUpdatedPictureInPictureModeWithBounds = true; + mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback; } @Override public boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds) { // TODO: Once we break the runs apart, we should fail() here if this is called outside // of onAnimationStart() and onAnimationEnd() - if (mRequestCancelAnimation) { + if (mCancelRequested) { + mCancelRequested = false; return false; } else { mBoundsUpdated = true; @@ -160,32 +170,206 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { } @Override - public void onAnimationEnd() { + public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackBounds, + boolean moveToFullscreen) { mAnimationEnded = true; + mAnimationEndFinalStackBounds = finalStackBounds; + mSchedulePipModeChangedOnEnd = schedulePipModeChangedCallback; + mMovedToFullscreen = moveToFullscreen; + mTaskBounds = null; } + } - @Override - public void moveToFullscreen() { - mMovedToFullscreen = true; + /** + * Drives the animations, makes common assertions along the way. + */ + private class BoundsAnimationDriver { + + private BoundsAnimationController mController; + private TestBoundsAnimationTarget mTarget; + private BoundsAnimator mAnimator; + + private Rect mFrom; + private Rect mTo; + private Rect mLargerBounds; + private Rect mExpectedFinalBounds; + + BoundsAnimationDriver(BoundsAnimationController controller, + TestBoundsAnimationTarget target) { + mController = controller; + mTarget = target; + } + + BoundsAnimationDriver start(Rect from, Rect to) { + if (mAnimator != null) { + throw new IllegalArgumentException("Call restart() to restart an animation"); + } + + mTarget.initialize(from); + + // Started, not running + assertTrue(mTarget.mAwaitingAnimationStart); + assertTrue(!mTarget.mAnimationStarted); + + startImpl(from, to); + + // Started and running + assertTrue(!mTarget.mAwaitingAnimationStart); + assertTrue(mTarget.mAnimationStarted); + + return this; + } + + BoundsAnimationDriver restart(Rect to) { + if (mAnimator == null) { + throw new IllegalArgumentException("Call start() to start a new animation"); + } + + BoundsAnimator oldAnimator = mAnimator; + boolean toSameBounds = mAnimator.isStarted() && to.equals(mTo); + + // Reset the animation start state + mTarget.mAnimationStarted = false; + + // Start animation + startImpl(mTarget.mStackBounds, to); + + if (toSameBounds) { + // Same animator if same final bounds + assertSame(oldAnimator, mAnimator); + } + + // No animation start for replacing animation + assertTrue(!mTarget.mAnimationStarted); + mTarget.mAnimationStarted = true; + return this; + } + + private BoundsAnimationDriver startImpl(Rect from, Rect to) { + boolean fromFullscreen = from.equals(BOUNDS_FULL); + boolean toFullscreen = to.equals(BOUNDS_FULL); + mFrom = new Rect(from); + mTo = new Rect(to); + mExpectedFinalBounds = new Rect(to); + mLargerBounds = getLargerBounds(mFrom, mTo); + + // Start animation + final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen + ? SCHEDULE_PIP_MODE_CHANGED_ON_START + : fromFullscreen + ? SCHEDULE_PIP_MODE_CHANGED_ON_END + : NO_PIP_MODE_CHANGED_CALLBACKS; + mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION, + schedulePipModeChangedState, toFullscreen); + + // Original stack bounds, frozen task bounds + assertEquals(mFrom, mTarget.mStackBounds); + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + + // Animating to larger size + if (mFrom.equals(mLargerBounds)) { + assertTrue(!mAnimator.animatingToLargerSize()); + } else if (mTo.equals(mLargerBounds)) { + assertTrue(mAnimator.animatingToLargerSize()); + } + + return this; + } + + BoundsAnimationDriver expectStarted(boolean schedulePipModeChanged) { + // Callback made + assertTrue(mTarget.mAnimationStarted); + + assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnStart); + return this; + } + + BoundsAnimationDriver update(float t) { + mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t)); + + // Temporary stack bounds, frozen task bounds + if (t == 0f) { + assertEquals(mFrom, mTarget.mStackBounds); + } else if (t == 1f) { + assertEquals(mTo, mTarget.mStackBounds); + } else { + assertNotEquals(mFrom, mTarget.mStackBounds); + assertNotEquals(mTo, mTarget.mStackBounds); + } + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + return this; + } + + BoundsAnimationDriver cancel() { + // Cancel + mTarget.mCancelRequested = true; + mTarget.mBoundsUpdated = false; + mExpectedFinalBounds = null; + + // Update + mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f)); + + // Not started, not running, cancel reset + assertTrue(!mTarget.mCancelRequested); + + // Stack/task bounds not updated + assertTrue(!mTarget.mBoundsUpdated); + + // Callback made + assertTrue(mTarget.mAnimationEnded); + assertNull(mTarget.mAnimationEndFinalStackBounds); + + return this; + } + + BoundsAnimationDriver end() { + mAnimator.end(); + + // Final stack bounds + assertEquals(mTo, mTarget.mStackBounds); + assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds); + assertNull(mTarget.mTaskBounds); + + return this; + } + + BoundsAnimationDriver expectEnded(boolean schedulePipModeChanged, + boolean moveToFullscreen) { + // Callback made + assertTrue(mTarget.mAnimationEnded); + + assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnEnd); + assertEquals(moveToFullscreen, mTarget.mMovedToFullscreen); + return this; + } + + private Rect getLargerBounds(Rect r1, Rect r2) { + int r1Area = r1.width() * r1.height(); + int r2Area = r2.width() * r2.height(); + if (r1Area <= r2Area) { + return r2; + } else { + return r1; + } } } // Constants + private static final boolean SCHEDULE_PIP_MODE_CHANGED = true; private static final boolean MOVE_TO_FULLSCREEN = true; + private static final int DURATION = 100; // Some dummy bounds to represent fullscreen and floating bounds private static final Rect BOUNDS_FULL = new Rect(0, 0, 100, 100); - private static final Rect BOUNDS_FLOATING = new Rect(80, 80, 95, 95); - private static final Rect BOUNDS_ALT_FLOATING = new Rect(60, 60, 95, 95); - - // Some dummy duration - private static final int DURATION = 100; + private static final Rect BOUNDS_FLOATING = new Rect(60, 60, 95, 95); + private static final Rect BOUNDS_SMALLER_FLOATING = new Rect(80, 80, 95, 95); // Common - private MockAppTransition mAppTransition; - private MockValueAnimator mAnimator; - private TestAnimateBoundsUser mTarget; + private MockAppTransition mMockAppTransition; + private MockValueAnimator mMockAnimator; + private TestBoundsAnimationTarget mTarget; private BoundsAnimationController mController; + private BoundsAnimationDriver mDriver; // Temp private Rect mTmpRect = new Rect(); @@ -196,153 +380,184 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { final Context context = InstrumentationRegistry.getTargetContext(); final Handler handler = new Handler(Looper.getMainLooper()); - mAppTransition = new MockAppTransition(context); - mAnimator = new MockValueAnimator(); - mTarget = new TestAnimateBoundsUser(); - mController = new BoundsAnimationController(context, mAppTransition, handler); + mMockAppTransition = new MockAppTransition(context); + mMockAnimator = new MockValueAnimator(); + mTarget = new TestBoundsAnimationTarget(); + mController = new BoundsAnimationController(context, mMockAppTransition, handler); + mDriver = new BoundsAnimationDriver(mController, mTarget); } + /** BASE TRANSITIONS **/ + @UiThreadTest @Test public void testFullscreenToFloatingTransition() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Assert that when we are started, and that we are not going to fullscreen - assertTrue(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationStartedToFullscreen); - // Ensure we are not triggering a PiP mode change - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); - // Ensure that the task stack bounds are already frozen to the larger source stack bounds - assertEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Drive some animation updates, ensure that only the stack bounds change and the task - // bounds are frozen to the original stack bounds (adjusted for the offset) - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - assertNotEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(1f)); - assertNotEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Finish the animation, ensure that it reaches the final bounds with the given state - boundsAnimator.end(); - assertTrue(mTarget.mAnimationEnded); - assertEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertNull(mTarget.mTaskBounds); + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } @UiThreadTest @Test public void testFloatingToFullscreenTransition() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FLOATING, - BOUNDS_FULL, DURATION, MOVE_TO_FULLSCREEN); - - // Assert that when we are started, and that we are going to fullscreen - assertTrue(mTarget.mAnimationStarted); - assertTrue(mTarget.mAnimationStartedToFullscreen); - // Ensure that we update the PiP mode change with the new fullscreen bounds - assertTrue(mTarget.mUpdatedPictureInPictureModeWithBounds); - // Ensure that the task stack bounds are already frozen to the larger target stack bounds - assertEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Drive some animation updates, ensure that only the stack bounds change and the task - // bounds are frozen to the original stack bounds (adjusted for the offset) - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(1f)); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Finish the animation, ensure that it reaches the final bounds with the given state - boundsAnimator.end(); - assertTrue(mTarget.mAnimationEnded); - assertEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertNull(mTarget.mTaskBounds); + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToSmallerFloatingTransition() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToLargerFloatingTransition() throws Exception { + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + /** F->!F w/ CANCEL **/ + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_SMALLER_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FULL) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); + } + + /** !F->F w/ CANCEL **/ + + @UiThreadTest + @Test + public void testFloatingToFullscreenCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FULL) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); } @UiThreadTest @Test - public void testInterruptAnimationFromUser() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Cancel the animation on the next update from the user - mTarget.mRequestCancelAnimation = true; - mTarget.mBoundsUpdated = false; - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - // Ensure that we got no more updates after returning false and the bounds are not updated - // to the end value - assertFalse(mTarget.mBoundsUpdated); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertNotEquals(BOUNDS_FLOATING, mTarget.mTaskBounds); - // Ensure that we received the animation end call - assertTrue(mTarget.mAnimationEnded); + public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_SMALLER_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } + /** !F->!F w/ CANCEL **/ + @UiThreadTest @Test - public void testCancelAnimationFromNewAnimationToExistingBounds() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Drive some animation updates - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - - // Cancel the animation as a restart to the same bounds - mTarget.reinitialize(null, null); - final BoundsAnimator altBoundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - // Ensure the animator is the same - assertSame(boundsAnimator, altBoundsAnimator); - // Ensure we haven't restarted or finished the animation - assertFalse(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationEnded); - // Ensure that we haven't tried to update the PiP mode - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); + public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } @UiThreadTest @Test - public void testCancelAnimationFromNewAnimationToNewBounds() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Drive some animation updates - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - - // Cancel the animation as a restart to new bounds - mTarget.reinitialize(null, null); - final BoundsAnimator altBoundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_ALT_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - // Ensure the animator is not the same - assertNotSame(boundsAnimator, altBoundsAnimator); - // Ensure that we did not get an animation start/end callback - assertFalse(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationEnded); - // Ensure that we haven't tried to update the PiP mode - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); + public void testFloatingToLargerFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + /** MISC **/ + + @UiThreadTest + @Test + public void testBoundsAreCopied() throws Exception { + Rect from = new Rect(0, 0, 100, 100); + Rect to = new Rect(25, 25, 75, 75); + mDriver.start(from, to) + .update(0.25f) + .end(); + assertEquals(new Rect(0, 0, 100, 100), from); + assertEquals(new Rect(25, 25, 75, 75), to); } /** - * @return the bounds offset to zero/zero. + * @return whether the task and stack bounds would be the same if they were at the same offset. */ - private Rect offsetToZero(Rect bounds) { - mTmpRect.set(bounds); - mTmpRect.offsetTo(0, 0); - return mTmpRect; + private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) { + mTmpRect.set(taskBounds); + mTmpRect.offsetTo(stackBounds.left, stackBounds.top); + return stackBounds.equals(mTmpRect); } } diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index 5ad7f8042c01..094c7bd89ba0 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -35,6 +35,7 @@ import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.ParcelableException; import android.os.StatFs; import android.os.SystemProperties; import android.os.UserHandle; @@ -150,7 +151,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { try { return mInstaller.isQuotaSupported(volumeUuid); } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } } @@ -163,7 +164,8 @@ public class StorageStatsService extends IStorageStatsManager.Stub { } else { final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); if (vol == null) { - throw new IllegalStateException("Volume was unexpected null"); + throw new ParcelableException( + new IOException("Failed to find storage device for UUID " + volumeUuid)); } return FileUtils.roundStorageSize(vol.disk.size); } @@ -189,7 +191,8 @@ public class StorageStatsService extends IStorageStatsManager.Stub { } else { final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); if (vol == null) { - throw new IllegalStateException("Volume was unexpected null"); + throw new ParcelableException( + new IOException("Failed to find storage device for UUID " + volumeUuid)); } return vol.getPath().getUsableSpace() + cacheBytes; } @@ -221,7 +224,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { appInfo = mPackage.getApplicationInfoAsUser(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); } catch (NameNotFoundException e) { - throw new IllegalStateException(e); + throw new ParcelableException(e); } if (mPackage.getPackagesForUid(appInfo.uid).length == 1) { @@ -239,7 +242,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { mInstaller.getAppSize(volumeUuid, packageNames, userId, 0, appId, ceDataInodes, codePaths, stats); } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -265,7 +268,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { codePaths[i] = mPackage.getApplicationInfoAsUser(packageNames[i], PackageManager.MATCH_UNINSTALLED_PACKAGES, userId).getCodePath(); } catch (NameNotFoundException e) { - throw new IllegalStateException(e); + throw new ParcelableException(e); } } @@ -281,7 +284,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("UID " + uid, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -313,7 +316,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("User " + userId, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -336,7 +339,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("External " + userId, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } final ExternalStorageStats res = new ExternalStorageStats(); diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 943a6cade853..eeaf2c121a75 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -19,18 +19,21 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; +import android.app.job.JobService; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.database.ContentObserver; import android.database.sqlite.SqliteWrapper; import android.net.Uri; +import android.telephony.Rlog; +import android.telephony.ServiceState; import android.telephony.SmsMessage; import android.telephony.SubscriptionManager; import android.text.TextUtils; -import android.telephony.Rlog; import android.util.Patterns; import com.android.internal.telephony.PhoneConstants; @@ -44,7 +47,7 @@ import java.util.regex.Pattern; /** * The Telephony provider contains data related to phone operation, specifically SMS and MMS - * messages and access to the APN list, including the MMSC to use. + * messages, access to the APN list, including the MMSC to use, and the service state. * * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered * devices. If your app depends on telephony features such as for managing SMS messages, include @@ -2972,4 +2975,272 @@ public final class Telephony { CMAS_CERTAINTY }; } + + /** + * Constants for interfacing with the ServiceStateProvider and the different fields of the + * {@link ServiceState} class accessible through the provider. + */ + public static final class ServiceStateTable { + + /** + * Not instantiable. + * @hide + */ + private ServiceStateTable() {} + + /** + * The authority string for the ServiceStateProvider + */ + public static final String AUTHORITY = "service-state"; + + /** + * The {@code content://} style URL for the ServiceStateProvider + */ + public static final Uri CONTENT_URI = Uri.parse("content://service-state/"); + + /** + * Generates a content {@link Uri} used to receive updates on a specific field in the + * ServiceState provider. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * ensure your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * + * @param subId the subId to receive updates on + * @param field the ServiceState field to receive updates on + * @return the Uri used to observe {@link ServiceState} changes + */ + public static Uri getUriForSubIdAndField(int subId, String field) { + return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)) + .appendEncodedPath(field).build(); + } + + /** + * Generates a content {@link Uri} used to receive updates on every field in the + * ServiceState provider. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * ensure your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * + * @param subId the subId to receive updates on + * @return the Uri used to observe {@link ServiceState} changes + */ + public static Uri getUriForSubId(int subId) { + return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)).build(); + } + + /** + * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance. + * + * @param state the ServiceState to convert into ContentValues + * @return the convertedContentValues instance + * @hide + */ + public static ContentValues getContentValuesForServiceState(ServiceState state) { + ContentValues values = new ContentValues(); + values.put(VOICE_REG_STATE, state.getVoiceRegState()); + values.put(DATA_REG_STATE, state.getDataRegState()); + values.put(VOICE_ROAMING_TYPE, state.getVoiceRoamingType()); + values.put(DATA_ROAMING_TYPE, state.getDataRoamingType()); + values.put(VOICE_OPERATOR_ALPHA_LONG, state.getVoiceOperatorAlphaLong()); + values.put(VOICE_OPERATOR_ALPHA_SHORT, state.getVoiceOperatorAlphaShort()); + values.put(VOICE_OPERATOR_NUMERIC, state.getVoiceOperatorNumeric()); + values.put(DATA_OPERATOR_ALPHA_LONG, state.getDataOperatorAlphaLong()); + values.put(DATA_OPERATOR_ALPHA_SHORT, state.getDataOperatorAlphaShort()); + values.put(DATA_OPERATOR_NUMERIC, state.getDataOperatorNumeric()); + values.put(IS_MANUAL_NETWORK_SELECTION, state.getIsManualSelection()); + values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology()); + values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology()); + values.put(CSS_INDICATOR, state.getCssIndicator()); + values.put(NETWORK_ID, state.getNetworkId()); + values.put(SYSTEM_ID, state.getSystemId()); + values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator()); + values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator()); + values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex()); + values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode()); + values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly()); + values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration()); + values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation()); + return values; + } + + /** + * An integer value indicating the current voice service state. + * <p> + * Valid values: {@link ServiceState#STATE_IN_SERVICE}, + * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY}, + * {@link ServiceState#STATE_POWER_OFF}. + * <p> + * This is the same as {@link ServiceState#getState()}. + */ + public static final String VOICE_REG_STATE = "voice_reg_state"; + + /** + * An integer value indicating the current data service state. + * <p> + * Valid values: {@link ServiceState#STATE_IN_SERVICE}, + * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY}, + * {@link ServiceState#STATE_POWER_OFF}. + * <p> + * This is the same as {@link ServiceState#getDataRegState()}. + * @hide + */ + public static final String DATA_REG_STATE = "data_reg_state"; + + /** + * An integer value indicating the current voice roaming type. + * <p> + * This is the same as {@link ServiceState#getVoiceRoamingType()}. + * @hide + */ + public static final String VOICE_ROAMING_TYPE = "voice_roaming_type"; + + /** + * An integer value indicating the current data roaming type. + * <p> + * This is the same as {@link ServiceState#getDataRoamingType()}. + * @hide + */ + public static final String DATA_ROAMING_TYPE = "data_roaming_type"; + + /** + * The current registered voice network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}. + * @hide + */ + public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long"; + + /** + * The current registered operator name in short alphanumeric format. + * <p> + * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice + * network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}. + * @hide + */ + public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short"; + + + /** + * The current registered operator numeric id. + * <p> + * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit + * network code. + * <p> + * This is the same as {@link ServiceState#getOperatorNumeric()}. + */ + public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + + /** + * The current registered data network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}. + * @hide + */ + public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long"; + + /** + * The current registered data network operator name in short alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}. + * @hide + */ + public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short"; + + /** + * The current registered data network operator numeric id. + * <p> + * This is the same as {@link ServiceState#getDataOperatorNumeric()}. + * @hide + */ + public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric"; + + /** + * The current network selection mode. + * <p> + * This is the same as {@link ServiceState#getIsManualSelection()}. + */ + public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + + /** + * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}. + * @hide + */ + public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology"; + + /** + * This is the same as {@link ServiceState#getRilDataRadioTechnology()}. + * @hide + */ + public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology"; + + /** + * This is the same as {@link ServiceState#getCssIndicator()}. + * @hide + */ + public static final String CSS_INDICATOR = "css_indicator"; + + /** + * This is the same as {@link ServiceState#getNetworkId()}. + * @hide + */ + public static final String NETWORK_ID = "network_id"; + + /** + * This is the same as {@link ServiceState#getSystemId()}. + * @hide + */ + public static final String SYSTEM_ID = "system_id"; + + /** + * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}. + * @hide + */ + public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator"; + + /** + * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}. + * @hide + */ + public static final String CDMA_DEFAULT_ROAMING_INDICATOR = + "cdma_default_roaming_indicator"; + + /** + * This is the same as {@link ServiceState#getCdmaEriIconIndex()}. + * @hide + */ + public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index"; + + /** + * This is the same as {@link ServiceState#getCdmaEriIconMode()}. + * @hide + */ + public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode"; + + /** + * This is the same as {@link ServiceState#isEmergencyOnly()}. + * @hide + */ + public static final String IS_EMERGENCY_ONLY = "is_emergency_only"; + + /** + * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}. + * @hide + */ + public static final String IS_DATA_ROAMING_FROM_REGISTRATION = + "is_data_roaming_from_registration"; + + /** + * This is the same as {@link ServiceState#isUsingCarrierAggregation()}. + * @hide + */ + public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation"; + } } |