diff options
231 files changed, 5815 insertions, 1742 deletions
diff --git a/api/current.txt b/api/current.txt index 732c50080623..8d1b4505d310 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5031,13 +5031,13 @@ package android.app { method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder); method public java.lang.CharSequence getCancelLabel(); method public java.lang.CharSequence getConfirmLabel(); - method public boolean getHintContentIntentLaunchesActivity(); + method public boolean getHintLaunchesActivity(); method public java.lang.CharSequence getInProgressLabel(); method public boolean isAvailableOffline(); method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean); method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence); method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence); - method public android.app.Notification.Action.WearableExtender setHintContentIntentLaunchesActivity(boolean); + method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean); method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence); } @@ -5901,7 +5901,7 @@ package android.app.admin { method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public int getOrganizationColor(android.content.ComponentName); - method public java.lang.String getOrganizationName(android.content.ComponentName); + method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); @@ -5976,7 +5976,7 @@ package android.app.admin { method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); method public void setOrganizationColor(android.content.ComponentName, int); - method public void setOrganizationName(android.content.ComponentName, java.lang.String); + method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence); method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -9497,11 +9497,8 @@ 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.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo); method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle); - method public int getShortcutIconResId(android.content.pm.ShortcutInfo); - method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle); method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle); method public boolean hasShortcutHostPermission(); method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle); @@ -10042,7 +10039,9 @@ package android.content.pm { public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivityComponent(); + method public java.util.List<java.lang.String> getCategories(); method public android.os.PersistableBundle getExtras(); + method public int getIconResourceId(); method public java.lang.String getId(); method public android.content.Intent getIntent(); method public long getLastChangedTimestamp(); @@ -10066,12 +10065,14 @@ package android.content.pm { field public static final int FLAG_HAS_ICON_RES = 4; // 0x4 field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10 field public static final int FLAG_PINNED = 2; // 0x2 + field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName); + method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String); @@ -10082,15 +10083,15 @@ package android.content.pm { } public class ShortcutManager { - method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo); - method public void deleteAllDynamicShortcuts(); - method public void deleteDynamicShortcut(java.lang.String); + method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts(); method public int getIconMaxDimensions(); method public int getMaxDynamicShortcutCount(); method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts(); method public long getRateLimitResetTime(); method public int getRemainingCallCount(); + method public void removeAllDynamicShortcuts(); + method public void removeDynamicShortcuts(java.util.List<java.lang.String>); method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>); } @@ -14436,13 +14437,13 @@ package android.hardware.camera2.params { public final class OutputConfiguration implements android.os.Parcelable { ctor public OutputConfiguration(android.view.Surface); + ctor public OutputConfiguration(int, android.view.Surface); method public int describeContents(); method public android.view.Surface getSurface(); - method public int getSurfaceSetId(); - method public void setSurfaceSetId(int); + method public int getSurfaceGroupId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR; - field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff + field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff } public final class RggbChannelVector { @@ -22966,6 +22967,7 @@ package android.media.tv { method public android.content.Intent createSettingsIntent(); method public android.content.Intent createSetupIntent(); method public int describeContents(); + method public android.os.Bundle getExtras(); method public java.lang.String getId(); method public java.lang.String getParentId(); method public android.content.pm.ServiceInfo getServiceInfo(); @@ -22995,6 +22997,7 @@ package android.media.tv { ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName); method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean); + method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle); method public android.media.tv.TvInputInfo.Builder setTunerCount(int); } @@ -29584,6 +29587,7 @@ package android.os.storage { public class StorageManager { 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 boolean isEncrypted(java.io.File); method public boolean isObbMounted(java.lang.String); @@ -49061,6 +49065,7 @@ package java.io { ctor public BufferedReader(java.io.Reader, int); ctor public BufferedReader(java.io.Reader); method public void close() throws java.io.IOException; + method public java.util.stream.Stream<java.lang.String> lines(); method public int read(char[], int, int) throws java.io.IOException; method public java.lang.String readLine() throws java.io.IOException; } @@ -49931,6 +49936,11 @@ package java.io { ctor public UTFDataFormatException(java.lang.String); } + public class UncheckedIOException extends java.lang.RuntimeException { + ctor public UncheckedIOException(java.lang.String, java.io.IOException); + ctor public UncheckedIOException(java.io.IOException); + } + public class UnsupportedEncodingException extends java.io.IOException { ctor public UnsupportedEncodingException(); ctor public UnsupportedEncodingException(java.lang.String); @@ -57587,6 +57597,7 @@ package java.util { method public void set(int, int); method public void set(int, int, boolean); method public int size(); + method public java.util.stream.IntStream stream(); method public byte[] toByteArray(); method public long[] toLongArray(); method public static java.util.BitSet valueOf(long[]); @@ -58042,6 +58053,7 @@ package java.util { method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); method public boolean replace(K, V, V); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set { @@ -58085,6 +58097,7 @@ package java.util { method public synchronized boolean remove(java.lang.Object, java.lang.Object); method public synchronized boolean replace(K, V, V); method public synchronized V replace(K, V); + method public synchronized void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public synchronized int size(); method public java.util.Collection<V> values(); } @@ -58625,6 +58638,18 @@ package java.util { public class Random implements java.io.Serializable { ctor public Random(); ctor public Random(long); + method public java.util.stream.DoubleStream doubles(long); + method public java.util.stream.DoubleStream doubles(); + method public java.util.stream.DoubleStream doubles(long, double, double); + method public java.util.stream.DoubleStream doubles(double, double); + method public java.util.stream.IntStream ints(long); + method public java.util.stream.IntStream ints(); + method public java.util.stream.IntStream ints(long, int, int); + method public java.util.stream.IntStream ints(int, int); + method public java.util.stream.LongStream longs(long); + method public java.util.stream.LongStream longs(); + method public java.util.stream.LongStream longs(long, long, long); + method public java.util.stream.LongStream longs(long, long); method protected int next(int); method public boolean nextBoolean(); method public void nextBytes(byte[]); @@ -59066,6 +59091,7 @@ package java.util { method public java.util.NavigableSet<K> navigableKeySet(); method public java.util.Map.Entry<K, V> pollFirstEntry(); method public java.util.Map.Entry<K, V> pollLastEntry(); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean); method public java.util.SortedMap<K, V> subMap(K, K); method public java.util.NavigableMap<K, V> tailMap(K, boolean); @@ -59167,6 +59193,7 @@ package java.util { ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>); method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } } @@ -60140,18 +60167,6 @@ package java.util.concurrent { public class ThreadLocalRandom extends java.util.Random { method public static java.util.concurrent.ThreadLocalRandom current(); - method public java.util.stream.DoubleStream doubles(long); - method public java.util.stream.DoubleStream doubles(); - method public java.util.stream.DoubleStream doubles(long, double, double); - method public java.util.stream.DoubleStream doubles(double, double); - method public java.util.stream.IntStream ints(long); - method public java.util.stream.IntStream ints(); - method public java.util.stream.IntStream ints(long, int, int); - method public java.util.stream.IntStream ints(int, int); - method public java.util.stream.LongStream longs(long); - method public java.util.stream.LongStream longs(); - method public java.util.stream.LongStream longs(long, long, long); - method public java.util.stream.LongStream longs(long, long); method public double nextDouble(double); method public double nextDouble(double, double); method public int nextInt(int, int); @@ -61524,6 +61539,7 @@ package java.util.regex { } public final class Pattern implements java.io.Serializable { + method public java.util.function.Predicate<java.lang.String> asPredicate(); method public static java.util.regex.Pattern compile(java.lang.String); method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException; method public int flags(); @@ -61533,6 +61549,7 @@ package java.util.regex { method public static java.lang.String quote(java.lang.String); method public java.lang.String[] split(java.lang.CharSequence, int); method public java.lang.String[] split(java.lang.CharSequence); + method public java.util.stream.Stream<java.lang.String> splitAsStream(java.lang.CharSequence); field public static final int CANON_EQ = 128; // 0x80 field public static final int CASE_INSENSITIVE = 2; // 0x2 field public static final int COMMENTS = 4; // 0x4 diff --git a/api/system-current.txt b/api/system-current.txt index 56b2f581bb82..b3bac02b62fe 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5165,13 +5165,13 @@ package android.app { method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder); method public java.lang.CharSequence getCancelLabel(); method public java.lang.CharSequence getConfirmLabel(); - method public boolean getHintContentIntentLaunchesActivity(); + method public boolean getHintLaunchesActivity(); method public java.lang.CharSequence getInProgressLabel(); method public boolean isAvailableOffline(); method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean); method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence); method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence); - method public android.app.Notification.Action.WearableExtender setHintContentIntentLaunchesActivity(boolean); + method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean); method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence); } @@ -6044,7 +6044,7 @@ package android.app.admin { method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public int getOrganizationColor(android.content.ComponentName); - method public java.lang.String getOrganizationName(android.content.ComponentName); + method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); @@ -6126,7 +6126,7 @@ package android.app.admin { method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); method public void setOrganizationColor(android.content.ComponentName, int); - method public void setOrganizationName(android.content.ComponentName, java.lang.String); + method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence); method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -9835,11 +9835,8 @@ 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.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo); method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle); - method public int getShortcutIconResId(android.content.pm.ShortcutInfo); - method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle); method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle); method public boolean hasShortcutHostPermission(); method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle); @@ -10442,7 +10439,9 @@ package android.content.pm { public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivityComponent(); + method public java.util.List<java.lang.String> getCategories(); method public android.os.PersistableBundle getExtras(); + method public int getIconResourceId(); method public java.lang.String getId(); method public android.content.Intent getIntent(); method public long getLastChangedTimestamp(); @@ -10466,12 +10465,14 @@ package android.content.pm { field public static final int FLAG_HAS_ICON_RES = 4; // 0x4 field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10 field public static final int FLAG_PINNED = 2; // 0x2 + field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName); + method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String); @@ -10482,15 +10483,15 @@ package android.content.pm { } public class ShortcutManager { - method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo); - method public void deleteAllDynamicShortcuts(); - method public void deleteDynamicShortcut(java.lang.String); + method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts(); method public int getIconMaxDimensions(); method public int getMaxDynamicShortcutCount(); method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts(); method public long getRateLimitResetTime(); method public int getRemainingCallCount(); + method public void removeAllDynamicShortcuts(); + method public void removeDynamicShortcuts(java.util.List<java.lang.String>); method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>); } @@ -14844,20 +14845,20 @@ package android.hardware.camera2.params { public final class OutputConfiguration implements android.os.Parcelable { ctor public OutputConfiguration(android.view.Surface); + ctor public OutputConfiguration(int, android.view.Surface); ctor public OutputConfiguration(android.view.Surface, int); - ctor public OutputConfiguration(android.hardware.camera2.params.OutputConfiguration); + ctor public OutputConfiguration(int, android.view.Surface, int); method public int describeContents(); method public int getRotation(); method public android.view.Surface getSurface(); - method public int getSurfaceSetId(); - method public void setSurfaceSetId(int); + method public int getSurfaceGroupId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR; field public static final int ROTATION_0 = 0; // 0x0 field public static final int ROTATION_180 = 2; // 0x2 field public static final int ROTATION_270 = 3; // 0x3 field public static final int ROTATION_90 = 1; // 0x1 - field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff + field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff } public final class RggbChannelVector { @@ -24623,6 +24624,7 @@ package android.media.tv { method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public int describeContents(); + method public android.os.Bundle getExtras(); method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo(); method public java.lang.String getId(); method public java.lang.String getParentId(); @@ -24656,6 +24658,7 @@ package android.media.tv { ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName); method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean); + method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle); method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo); method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon); method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int); @@ -31890,6 +31893,7 @@ package android.os.storage { public class StorageManager { 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 boolean isEncrypted(java.io.File); method public boolean isObbMounted(java.lang.String); @@ -52174,6 +52178,7 @@ package java.io { ctor public BufferedReader(java.io.Reader, int); ctor public BufferedReader(java.io.Reader); method public void close() throws java.io.IOException; + method public java.util.stream.Stream<java.lang.String> lines(); method public int read(char[], int, int) throws java.io.IOException; method public java.lang.String readLine() throws java.io.IOException; } @@ -53044,6 +53049,11 @@ package java.io { ctor public UTFDataFormatException(java.lang.String); } + public class UncheckedIOException extends java.lang.RuntimeException { + ctor public UncheckedIOException(java.lang.String, java.io.IOException); + ctor public UncheckedIOException(java.io.IOException); + } + public class UnsupportedEncodingException extends java.io.IOException { ctor public UnsupportedEncodingException(); ctor public UnsupportedEncodingException(java.lang.String); @@ -60700,6 +60710,7 @@ package java.util { method public void set(int, int); method public void set(int, int, boolean); method public int size(); + method public java.util.stream.IntStream stream(); method public byte[] toByteArray(); method public long[] toLongArray(); method public static java.util.BitSet valueOf(long[]); @@ -61155,6 +61166,7 @@ package java.util { method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); method public boolean replace(K, V, V); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set { @@ -61198,6 +61210,7 @@ package java.util { method public synchronized boolean remove(java.lang.Object, java.lang.Object); method public synchronized boolean replace(K, V, V); method public synchronized V replace(K, V); + method public synchronized void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public synchronized int size(); method public java.util.Collection<V> values(); } @@ -61738,6 +61751,18 @@ package java.util { public class Random implements java.io.Serializable { ctor public Random(); ctor public Random(long); + method public java.util.stream.DoubleStream doubles(long); + method public java.util.stream.DoubleStream doubles(); + method public java.util.stream.DoubleStream doubles(long, double, double); + method public java.util.stream.DoubleStream doubles(double, double); + method public java.util.stream.IntStream ints(long); + method public java.util.stream.IntStream ints(); + method public java.util.stream.IntStream ints(long, int, int); + method public java.util.stream.IntStream ints(int, int); + method public java.util.stream.LongStream longs(long); + method public java.util.stream.LongStream longs(); + method public java.util.stream.LongStream longs(long, long, long); + method public java.util.stream.LongStream longs(long, long); method protected int next(int); method public boolean nextBoolean(); method public void nextBytes(byte[]); @@ -62179,6 +62204,7 @@ package java.util { method public java.util.NavigableSet<K> navigableKeySet(); method public java.util.Map.Entry<K, V> pollFirstEntry(); method public java.util.Map.Entry<K, V> pollLastEntry(); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean); method public java.util.SortedMap<K, V> subMap(K, K); method public java.util.NavigableMap<K, V> tailMap(K, boolean); @@ -62280,6 +62306,7 @@ package java.util { ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>); method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } } @@ -63253,18 +63280,6 @@ package java.util.concurrent { public class ThreadLocalRandom extends java.util.Random { method public static java.util.concurrent.ThreadLocalRandom current(); - method public java.util.stream.DoubleStream doubles(long); - method public java.util.stream.DoubleStream doubles(); - method public java.util.stream.DoubleStream doubles(long, double, double); - method public java.util.stream.DoubleStream doubles(double, double); - method public java.util.stream.IntStream ints(long); - method public java.util.stream.IntStream ints(); - method public java.util.stream.IntStream ints(long, int, int); - method public java.util.stream.IntStream ints(int, int); - method public java.util.stream.LongStream longs(long); - method public java.util.stream.LongStream longs(); - method public java.util.stream.LongStream longs(long, long, long); - method public java.util.stream.LongStream longs(long, long); method public double nextDouble(double); method public double nextDouble(double, double); method public int nextInt(int, int); @@ -64637,6 +64652,7 @@ package java.util.regex { } public final class Pattern implements java.io.Serializable { + method public java.util.function.Predicate<java.lang.String> asPredicate(); method public static java.util.regex.Pattern compile(java.lang.String); method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException; method public int flags(); @@ -64646,6 +64662,7 @@ package java.util.regex { method public static java.lang.String quote(java.lang.String); method public java.lang.String[] split(java.lang.CharSequence, int); method public java.lang.String[] split(java.lang.CharSequence); + method public java.util.stream.Stream<java.lang.String> splitAsStream(java.lang.CharSequence); field public static final int CANON_EQ = 128; // 0x80 field public static final int CASE_INSENSITIVE = 2; // 0x2 field public static final int COMMENTS = 4; // 0x4 diff --git a/api/test-current.txt b/api/test-current.txt index 679347df0feb..fcfe489c8e38 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5031,13 +5031,13 @@ package android.app { method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder); method public java.lang.CharSequence getCancelLabel(); method public java.lang.CharSequence getConfirmLabel(); - method public boolean getHintContentIntentLaunchesActivity(); + method public boolean getHintLaunchesActivity(); method public java.lang.CharSequence getInProgressLabel(); method public boolean isAvailableOffline(); method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean); method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence); method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence); - method public android.app.Notification.Action.WearableExtender setHintContentIntentLaunchesActivity(boolean); + method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean); method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence); } @@ -5905,7 +5905,7 @@ package android.app.admin { method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public int getOrganizationColor(android.content.ComponentName); - method public java.lang.String getOrganizationName(android.content.ComponentName); + method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); @@ -5980,7 +5980,7 @@ package android.app.admin { method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); method public void setOrganizationColor(android.content.ComponentName, int); - method public void setOrganizationName(android.content.ComponentName, java.lang.String); + method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence); method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -9507,11 +9507,8 @@ 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.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo); method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle); - method public int getShortcutIconResId(android.content.pm.ShortcutInfo); - method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle); method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle); method public boolean hasShortcutHostPermission(); method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle); @@ -10053,7 +10050,9 @@ package android.content.pm { public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivityComponent(); + method public java.util.List<java.lang.String> getCategories(); method public android.os.PersistableBundle getExtras(); + method public int getIconResourceId(); method public java.lang.String getId(); method public android.content.Intent getIntent(); method public long getLastChangedTimestamp(); @@ -10077,12 +10076,14 @@ package android.content.pm { field public static final int FLAG_HAS_ICON_RES = 4; // 0x4 field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10 field public static final int FLAG_PINNED = 2; // 0x2 + field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName); + method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String); @@ -10094,15 +10095,15 @@ package android.content.pm { public class ShortcutManager { ctor public ShortcutManager(android.content.Context); - method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo); - method public void deleteAllDynamicShortcuts(); - method public void deleteDynamicShortcut(java.lang.String); + method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts(); method public int getIconMaxDimensions(); method public int getMaxDynamicShortcutCount(); method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts(); method public long getRateLimitResetTime(); method public int getRemainingCallCount(); + method public void removeAllDynamicShortcuts(); + method public void removeDynamicShortcuts(java.util.List<java.lang.String>); method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>); method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>); } @@ -14448,13 +14449,13 @@ package android.hardware.camera2.params { public final class OutputConfiguration implements android.os.Parcelable { ctor public OutputConfiguration(android.view.Surface); + ctor public OutputConfiguration(int, android.view.Surface); method public int describeContents(); method public android.view.Surface getSurface(); - method public int getSurfaceSetId(); - method public void setSurfaceSetId(int); + method public int getSurfaceGroupId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR; - field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff + field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff } public final class RggbChannelVector { @@ -23034,6 +23035,7 @@ package android.media.tv { method public android.content.Intent createSettingsIntent(); method public android.content.Intent createSetupIntent(); method public int describeContents(); + method public android.os.Bundle getExtras(); method public java.lang.String getId(); method public java.lang.String getParentId(); method public android.content.pm.ServiceInfo getServiceInfo(); @@ -23063,6 +23065,7 @@ package android.media.tv { ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName); method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean); + method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle); method public android.media.tv.TvInputInfo.Builder setTunerCount(int); } @@ -29653,6 +29656,7 @@ package android.os.storage { public class StorageManager { 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 boolean isEncrypted(java.io.File); method public boolean isObbMounted(java.lang.String); @@ -49139,6 +49143,7 @@ package java.io { ctor public BufferedReader(java.io.Reader, int); ctor public BufferedReader(java.io.Reader); method public void close() throws java.io.IOException; + method public java.util.stream.Stream<java.lang.String> lines(); method public int read(char[], int, int) throws java.io.IOException; method public java.lang.String readLine() throws java.io.IOException; } @@ -50009,6 +50014,11 @@ package java.io { ctor public UTFDataFormatException(java.lang.String); } + public class UncheckedIOException extends java.lang.RuntimeException { + ctor public UncheckedIOException(java.lang.String, java.io.IOException); + ctor public UncheckedIOException(java.io.IOException); + } + public class UnsupportedEncodingException extends java.io.IOException { ctor public UnsupportedEncodingException(); ctor public UnsupportedEncodingException(java.lang.String); @@ -57665,6 +57675,7 @@ package java.util { method public void set(int, int); method public void set(int, int, boolean); method public int size(); + method public java.util.stream.IntStream stream(); method public byte[] toByteArray(); method public long[] toLongArray(); method public static java.util.BitSet valueOf(long[]); @@ -58120,6 +58131,7 @@ package java.util { method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); method public boolean replace(K, V, V); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set { @@ -58163,6 +58175,7 @@ package java.util { method public synchronized boolean remove(java.lang.Object, java.lang.Object); method public synchronized boolean replace(K, V, V); method public synchronized V replace(K, V); + method public synchronized void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public synchronized int size(); method public java.util.Collection<V> values(); } @@ -58703,6 +58716,18 @@ package java.util { public class Random implements java.io.Serializable { ctor public Random(); ctor public Random(long); + method public java.util.stream.DoubleStream doubles(long); + method public java.util.stream.DoubleStream doubles(); + method public java.util.stream.DoubleStream doubles(long, double, double); + method public java.util.stream.DoubleStream doubles(double, double); + method public java.util.stream.IntStream ints(long); + method public java.util.stream.IntStream ints(); + method public java.util.stream.IntStream ints(long, int, int); + method public java.util.stream.IntStream ints(int, int); + method public java.util.stream.LongStream longs(long); + method public java.util.stream.LongStream longs(); + method public java.util.stream.LongStream longs(long, long, long); + method public java.util.stream.LongStream longs(long, long); method protected int next(int); method public boolean nextBoolean(); method public void nextBytes(byte[]); @@ -59144,6 +59169,7 @@ package java.util { method public java.util.NavigableSet<K> navigableKeySet(); method public java.util.Map.Entry<K, V> pollFirstEntry(); method public java.util.Map.Entry<K, V> pollLastEntry(); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean); method public java.util.SortedMap<K, V> subMap(K, K); method public java.util.NavigableMap<K, V> tailMap(K, boolean); @@ -59245,6 +59271,7 @@ package java.util { ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>); method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); method public void forEach(java.util.function.BiConsumer<? super K, ? super V>); + method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>); } } @@ -60218,18 +60245,6 @@ package java.util.concurrent { public class ThreadLocalRandom extends java.util.Random { method public static java.util.concurrent.ThreadLocalRandom current(); - method public java.util.stream.DoubleStream doubles(long); - method public java.util.stream.DoubleStream doubles(); - method public java.util.stream.DoubleStream doubles(long, double, double); - method public java.util.stream.DoubleStream doubles(double, double); - method public java.util.stream.IntStream ints(long); - method public java.util.stream.IntStream ints(); - method public java.util.stream.IntStream ints(long, int, int); - method public java.util.stream.IntStream ints(int, int); - method public java.util.stream.LongStream longs(long); - method public java.util.stream.LongStream longs(); - method public java.util.stream.LongStream longs(long, long, long); - method public java.util.stream.LongStream longs(long, long); method public double nextDouble(double); method public double nextDouble(double, double); method public int nextInt(int, int); @@ -61602,6 +61617,7 @@ package java.util.regex { } public final class Pattern implements java.io.Serializable { + method public java.util.function.Predicate<java.lang.String> asPredicate(); method public static java.util.regex.Pattern compile(java.lang.String); method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException; method public int flags(); @@ -61611,6 +61627,7 @@ package java.util.regex { method public static java.lang.String quote(java.lang.String); method public java.lang.String[] split(java.lang.CharSequence, int); method public java.lang.String[] split(java.lang.CharSequence); + method public java.util.stream.Stream<java.lang.String> splitAsStream(java.lang.CharSequence); field public static final int CANON_EQ = 128; // 0x80 field public static final int CASE_INSENSITIVE = 2; // 0x2 field public static final int COMMENTS = 4; // 0x4 diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d1f514327731..631a1293cdc0 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Matrix; @@ -1305,6 +1306,12 @@ public class ActivityManager { */ public boolean isDockable; + /** + * The resize mode of the task. See {@link ActivityInfo#resizeMode}. + * @hide + */ + public int resizeMode; + public RecentTaskInfo() { } @@ -1349,6 +1356,7 @@ public class ActivityManager { dest.writeInt(0); } dest.writeInt(isDockable ? 1 : 0); + dest.writeInt(resizeMode); } public void readFromParcel(Parcel source) { @@ -1372,6 +1380,7 @@ public class ActivityManager { bounds = source.readInt() > 0 ? Rect.CREATOR.createFromParcel(source) : null; isDockable = source.readInt() == 1; + resizeMode = source.readInt(); } public static final Creator<RecentTaskInfo> CREATOR @@ -1560,6 +1569,12 @@ public class ActivityManager { */ public boolean isDockable; + /** + * The resize mode of the task. See {@link ActivityInfo#resizeMode}. + * @hide + */ + public int resizeMode; + public RunningTaskInfo() { } @@ -1583,6 +1598,7 @@ public class ActivityManager { dest.writeInt(numActivities); dest.writeInt(numRunning); dest.writeInt(isDockable ? 1 : 0); + dest.writeInt(resizeMode); } public void readFromParcel(Parcel source) { @@ -1599,6 +1615,7 @@ public class ActivityManager { numActivities = source.readInt(); numRunning = source.readInt(); isDockable = source.readInt() != 0; + resizeMode = source.readInt(); } public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index ed590e6270e4..bf56f2513257 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1921,6 +1921,16 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public void deleteApplicationCacheFilesAsUser(String packageName, int userId, + IPackageDataObserver observer) { + try { + mPM.deleteApplicationCacheFilesAsUser(packageName, userId, observer); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override public void freeStorageAndNotify(String volumeUuid, long idealStorageSize, IPackageDataObserver observer) { try { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 784872cedaa2..052874f77ce6 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -29,6 +29,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; @@ -43,6 +44,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.os.UserHandle; +import android.text.BidiFormatter; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -588,8 +590,8 @@ public class Notification implements Parcelable private static final int COLOR_INVALID = 1; /** - * Sphere of visibility of this notification, which affects how and when the SystemUI reveals - * the notification's presence and contents in untrusted situations (namely, on the secure + * Sphere of visibility of this notification, which affects how and when the SystemUI reveals + * the notification's presence and contents in untrusted situations (namely, on the secure * lockscreen). * * The default level, {@link #VISIBILITY_PRIVATE}, behaves exactly as notifications have always @@ -1419,7 +1421,7 @@ public class Notification implements Parcelable * an activity and transitions should be generated, false otherwise. * @return this object for method chaining */ - public WearableExtender setHintContentIntentLaunchesActivity( + public WearableExtender setHintLaunchesActivity( boolean hintLaunchesActivity) { setFlag(FLAG_HINT_LAUNCHES_ACTIVITY, hintLaunchesActivity); return this; @@ -1432,7 +1434,7 @@ public class Notification implements Parcelable * should be generated, false otherwise. The default value is {@code false} if this was * never set. */ - public boolean getHintContentIntentLaunchesActivity() { + public boolean getHintLaunchesActivity() { return (mFlags & FLAG_HINT_LAUNCHES_ACTIVITY) != 0; } } @@ -2227,7 +2229,8 @@ public class Notification implements Parcelable Log.d(TAG, "Unknown style class: " + templateClass); } else { try { - final Constructor<? extends Style> ctor = styleClass.getConstructor(); + final Constructor<? extends Style> ctor = + styleClass.getDeclaredConstructor(); ctor.setAccessible(true); final Style style = ctor.newInstance(); style.restoreFromExtras(mN.extras); @@ -3126,6 +3129,18 @@ public class Notification implements Parcelable * @param hasProgress whether the progress bar should be shown and set */ private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) { + final Bundle ex = mN.extras; + + CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE)); + CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT)); + return applyStandardTemplate(resId, hasProgress, title, text); + } + + /** + * @param hasProgress whether the progress bar should be shown and set + */ + private RemoteViews applyStandardTemplate(int resId, boolean hasProgress, + CharSequence title, CharSequence text) { RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); resetStandardTemplate(contentView); @@ -3134,17 +3149,15 @@ public class Notification implements Parcelable bindNotificationHeader(contentView); bindLargeIcon(contentView); - if (ex.getCharSequence(EXTRA_TITLE) != null) { + if (title != null) { contentView.setViewVisibility(R.id.title, View.VISIBLE); - contentView.setTextViewText(R.id.title, - processLegacyText(ex.getCharSequence(EXTRA_TITLE))); + contentView.setTextViewText(R.id.title, title); } boolean showProgress = handleProgressBar(hasProgress, contentView, ex); - if (ex.getCharSequence(EXTRA_TEXT) != null) { + if (text != null) { int textId = showProgress ? com.android.internal.R.id.text_line_1 : com.android.internal.R.id.text; - contentView.setTextViewText(textId, processLegacyText( - ex.getCharSequence(EXTRA_TEXT))); + contentView.setTextViewText(textId, text); contentView.setViewVisibility(textId, View.VISIBLE); } @@ -3295,7 +3308,16 @@ public class Notification implements Parcelable } private RemoteViews applyStandardTemplateWithActions(int layoutId) { - RemoteViews big = applyStandardTemplate(layoutId); + final Bundle ex = mN.extras; + + CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE)); + CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT)); + return applyStandardTemplateWithActions(layoutId, true /* hasProgress */, title, text); + } + + private RemoteViews applyStandardTemplateWithActions(int layoutId, boolean hasProgress, + CharSequence title, CharSequence text) { + RemoteViews big = applyStandardTemplate(layoutId, hasProgress, title, text); resetStandardTemplateWithActions(big); @@ -3749,6 +3771,10 @@ public class Notification implements Parcelable return R.layout.notification_template_material_inbox; } + private int getMessagingLayoutResource() { + return R.layout.notification_template_material_messaging; + } + private int getActionLayoutResource() { return R.layout.notification_material_action; } @@ -4375,13 +4401,100 @@ public class Notification implements Parcelable /** * @hide */ + @Override + public RemoteViews makeContentView() { + Message m = findLatestIncomingMessage(); + CharSequence title = mConversationTitle != null + ? mConversationTitle + : (m == null) ? null : m.mSender; + CharSequence text = (m == null) + ? null + : mConversationTitle != null ? makeMessageLine(m) : m.mText; + + return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(), + false /* hasProgress */, + title, + text); + } + + private Message findLatestIncomingMessage() { + for (int i = mMessages.size() - 1; i >= 0; i--) { + Message m = mMessages.get(i); + // Incoming messages have a non-empty sender. + if (!TextUtils.isEmpty(m.mSender)) { + return m; + } + } + return null; + } + + /** + * @hide + */ + @Override public RemoteViews makeBigContentView() { - // TODO handset to write implementation - RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); + CharSequence title = !TextUtils.isEmpty(super.mBigContentTitle) + ? super.mBigContentTitle + : mConversationTitle; + boolean hasTitle = !TextUtils.isEmpty(title); + + RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( + mBuilder.getMessagingLayoutResource(), + false /* hasProgress */, + title, + null /* text */); + + int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3, + R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6}; + + // Make sure all rows are gone in case we reuse a view. + for (int rowId : rowIds) { + contentView.setViewVisibility(rowId, View.GONE); + } + int i=0; + int titlePadding = mBuilder.mContext.getResources().getDimensionPixelSize( + R.dimen.notification_messaging_spacing); + contentView.setViewLayoutMarginBottom(R.id.line1, hasTitle ? titlePadding : 0); + contentView.setInt(R.id.notification_messaging, "setNumIndentLines", + mBuilder.mN.mLargeIcon == null ? 0 : (hasTitle ? 1 : 2)); + + int firstMessage = Math.max(0, mMessages.size() - rowIds.length); + while (firstMessage + i < mMessages.size() && i < rowIds.length) { + Message m = mMessages.get(firstMessage + i); + int rowId = rowIds[i]; + + contentView.setViewVisibility(rowId, View.VISIBLE); + contentView.setTextViewText(rowId, makeMessageLine(m)); + + i++; + } return contentView; } + private CharSequence makeMessageLine(Message m) { + BidiFormatter bidi = BidiFormatter.getInstance(); + SpannableStringBuilder sb = new SpannableStringBuilder(); + if (TextUtils.isEmpty(m.mSender)) { + CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName; + sb.append(bidi.unicodeWrap(replyName), + makeFontColorSpan(mBuilder.resolveContrastColor()), + 0 /* flags */); + } else { + sb.append(bidi.unicodeWrap(m.mSender), + makeFontColorSpan(Color.BLACK), + 0 /* flags */); + } + CharSequence text = m.mText == null ? "" : m.mText; + sb.append(" ").append(bidi.unicodeWrap(text)); + return sb; + } + + private static TextAppearanceSpan makeFontColorSpan(int color) { + return new TextAppearanceSpan(null, 0, 0, + ColorStateList.valueOf(color), null); + } + public static final class Message implements Parcelable { private final CharSequence mText; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 96757bba510d..a7bb34840522 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6050,11 +6050,13 @@ public class DevicePolicyManager { * {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param color The 32bit representation of the color to be used. + * @param color The 24bit (0xRRGGBB) representation of the color to be used. * @throws SecurityException if {@code admin} is not a profile owner. */ public void setOrganizationColor(@NonNull ComponentName admin, int color) { try { + // always enforce alpha channel to have 100% opacity + color |= 0xFF000000; mService.setOrganizationColor(admin, color); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -6066,7 +6068,7 @@ public class DevicePolicyManager { * * Sets the color used for customization. * - * @param color The 32bit representation of the color to be used. + * @param color The 24bit (0xRRGGBB) representation of the color to be used. * @param userId which user to set the color to. * @RequiresPermission(allOf = { * Manifest.permission.MANAGE_USERS, @@ -6074,6 +6076,8 @@ public class DevicePolicyManager { */ public void setOrganizationColorForUser(@ColorInt int color, @UserIdInt int userId) { try { + // always enforce alpha channel to have 100% opacity + color |= 0xFF000000; mService.setOrganizationColorForUser(color, userId); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -6085,10 +6089,10 @@ public class DevicePolicyManager { * This color is used as background color of the confirm credentials screen for that user. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @return The 32bit representation of the color to be used. + * @return The 24bit (0xRRGGBB) representation of the color to be used. * @throws SecurityException if {@code admin} is not a profile owner. */ - public int getOrganizationColor(@NonNull ComponentName admin) { + public @ColorInt int getOrganizationColor(@NonNull ComponentName admin) { try { return mService.getOrganizationColor(admin); } catch (RemoteException re) { @@ -6101,9 +6105,9 @@ public class DevicePolicyManager { * Retrieve the customization color for a given user. * * @param userHandle The user id of the user we're interested in. - * @return The 32bit representation of the color to be used. + * @return The 24bit (0xRRGGBB) representation of the color to be used. */ - public int getOrganizationColorForUser(int userHandle) { + public @ColorInt int getOrganizationColorForUser(int userHandle) { try { return mService.getOrganizationColorForUser(userHandle); } catch (RemoteException re) { @@ -6123,7 +6127,7 @@ public class DevicePolicyManager { * @param title The organization name or {@code null} to clear a previously set name. * @throws SecurityException if {@code admin} is not a profile owner. */ - public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) { + public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) { try { mService.setOrganizationName(admin, title); } catch (RemoteException re) { @@ -6139,7 +6143,7 @@ public class DevicePolicyManager { * @return The organization name or {@code null} if none is set. * @throws SecurityException if {@code admin} is not a profile owner. */ - public String getOrganizationName(@NonNull ComponentName admin) { + public CharSequence getOrganizationName(@NonNull ComponentName admin) { try { return mService.getOrganizationName(admin); } catch (RemoteException re) { @@ -6155,7 +6159,7 @@ public class DevicePolicyManager { * * @hide */ - public String getOrganizationNameForUser(int userHandle) { + public CharSequence getOrganizationNameForUser(int userHandle) { try { return mService.getOrganizationNameForUser(userHandle); } catch (RemoteException re) { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 6df10388b85e..2801b8779fc7 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -284,9 +284,9 @@ interface IDevicePolicyManager { int getOrganizationColor(in ComponentName admin); int getOrganizationColorForUser(int userHandle); - void setOrganizationName(in ComponentName admin, in String title); - String getOrganizationName(in ComponentName admin); - String getOrganizationNameForUser(int userHandle); + void setOrganizationName(in ComponentName admin, in CharSequence title); + CharSequence getOrganizationName(in ComponentName admin); + CharSequence getOrganizationNameForUser(int userHandle); int getUserProvisioningState(); void setUserProvisioningState(int state, int userHandle); diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 828ac385b62d..9b4f43ae9feb 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -254,7 +254,8 @@ public class JobInfo implements Parcelable { } /** - * Flex time for this job. Only valid if this is a periodic job. + * Flex time for this job. Only valid if this is a periodic job. The job can + * execute at any time in a window of flex length at the end of the period. */ public long getFlexMillis() { long interval = getIntervalMillis(); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 104feb5dc7cd..585d2a3c4b25 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -366,6 +366,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * <p>NOTE: {@code WebView} does not honor this flag. * + * <p>This flag is ignored on Android N and above if an Android Network Security Config is + * present. + * * <p>This flag comes from * {@link android.R.styleable#AndroidManifestApplication_usesCleartextTraffic * android:usesCleartextTraffic} of the <application> tag. diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 46321a4d7027..430c7e706b64 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -18,6 +18,7 @@ package android.content.pm; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IOnAppsChangedListener; import android.content.pm.ParceledListSlice; @@ -37,7 +38,7 @@ interface ILauncherApps { void addOnAppsChangedListener(String callingPackage, in IOnAppsChangedListener listener); void removeOnAppsChangedListener(in IOnAppsChangedListener listener); ParceledListSlice getLauncherActivities(String packageName, in UserHandle user); - ResolveInfo resolveActivity(in Intent intent, in UserHandle user); + ActivityInfo resolveActivity(in ComponentName component, in UserHandle user); void startActivityAsUser(in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds, diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 6fce36be43ab..0526815abc5a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -388,6 +388,15 @@ interface IPackageManager { void deleteApplicationCacheFiles(in String packageName, IPackageDataObserver observer); /** + * Delete all the cache files in an applications cache directory + * @param packageName The package name of the application whose cache + * files need to be deleted + * @param userId the user to delete application cache for + * @param observer a callback used to notify when the deletion is finished. + */ + void deleteApplicationCacheFilesAsUser(in String packageName, int userId, IPackageDataObserver observer); + + /** * Clear the user data directory of an application. * @param packageName The package name of the application whose cache * files need to be deleted diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl index 31d377b554f8..9c90346a075c 100644 --- a/core/java/android/content/pm/IShortcutService.aidl +++ b/core/java/android/content/pm/IShortcutService.aidl @@ -28,11 +28,12 @@ interface IShortcutService { ParceledListSlice getDynamicShortcuts(String packageName, int userId); - boolean addDynamicShortcut(String packageName, in ShortcutInfo shortcutInfo, int userId); + boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList, + int userId); - void deleteDynamicShortcut(String packageName, in String shortcutId, int userId); + void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId); - void deleteAllDynamicShortcuts(String packageName, int userId); + void removeAllDynamicShortcuts(String packageName, int userId); ParceledListSlice getPinnedShortcuts(String packageName, int userId); diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index 40e1a9f8ba79..2beca7bb6022 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -39,7 +39,6 @@ public class LauncherActivityInfo { private ActivityInfo mActivityInfo; private ComponentName mComponentName; - private ResolveInfo mResolveInfo; private UserHandle mUser; /** @@ -49,11 +48,10 @@ public class LauncherActivityInfo { * @param info ResolveInfo from which to create the LauncherActivityInfo. * @param user The UserHandle of the profile to which this activity belongs. */ - LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user) { + LauncherActivityInfo(Context context, ActivityInfo info, UserHandle user) { this(context); - mResolveInfo = info; - mActivityInfo = info.activityInfo; - mComponentName = LauncherApps.getComponentName(info); + mActivityInfo = info; + mComponentName = new ComponentName(info.packageName, info.name); mUser = user; } @@ -91,7 +89,7 @@ public class LauncherActivityInfo { * @return The label for the activity. */ public CharSequence getLabel() { - return mResolveInfo.loadLabel(mPm); + return mActivityInfo.loadLabel(mPm); } /** @@ -103,7 +101,7 @@ public class LauncherActivityInfo { * @return The drawable associated with the activity. */ public Drawable getIcon(int density) { - final int iconRes = mResolveInfo.getIconResourceInternal(); + final int iconRes = mActivityInfo.getIconResource(); Drawable icon = null; // Get the preferred density icon from the app's resources if (density != 0 && iconRes != 0) { @@ -116,7 +114,7 @@ public class LauncherActivityInfo { } // Get the default density icon if (icon == null) { - icon = mResolveInfo.loadIcon(mPm); + icon = mActivityInfo.loadIcon(mPm); } return icon; } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index a0d2339566a5..824722d70fad 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -39,6 +39,7 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -291,7 +292,7 @@ public class LauncherApps { } ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>(); for (ResolveInfo ri : activities.getList()) { - LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user); + LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user); if (DEBUG) { Log.v(TAG, "Returning activity for profile " + user + " : " + lai.getComponentName()); @@ -301,10 +302,6 @@ public class LauncherApps { return lais; } - static ComponentName getComponentName(ResolveInfo ri) { - return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name); - } - /** * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it * returns null. @@ -315,9 +312,9 @@ public class LauncherApps { */ public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { try { - ResolveInfo ri = mService.resolveActivity(intent, user); - if (ri != null) { - LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user); + ActivityInfo ai = mService.resolveActivity(intent.getComponent(), user); + if (ai != null) { + LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user); return info; } } catch (RemoteException re) { @@ -389,6 +386,7 @@ public class LauncherApps { * * @return An {@link ApplicationInfo} containing information about the package or * null of the package isn't found. + * @hide */ public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, UserHandle user) { @@ -493,43 +491,24 @@ public class LauncherApps { } /** - * Return the icon resource ID, if {@code shortcut} has one - * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}). - * - * <p>Callers must be allowed to access the shortcut information, as defined in {@link - * #hasShortcutHostPermission()}. - * - * @param shortcut The target shortcut. + * @hide kept for testing. */ public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) { - return getShortcutIconResId(shortcut.getPackageName(), shortcut.getId(), - shortcut.getUserId()); + return shortcut.getIconResourceId(); } /** - * Return the icon resource ID, if {@code shortcut} has one - * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}). - * - * <p>Callers must be allowed to access the shortcut information, as defined in {@link - * #hasShortcutHostPermission()}. - * - * @param packageName The target package name. - * @param shortcutId The ID of the shortcut to lad rom. - * @param user The UserHandle of the profile. + * @hide kept for testing. */ public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) { - return getShortcutIconResId(packageName, shortcutId, user.getIdentifier()); - } + final ShortcutQuery q = new ShortcutQuery(); + q.setPackage(packageName); + q.setShortcutIds(Arrays.asList(shortcutId)); + q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED); + final List<ShortcutInfo> shortcuts = getShortcuts(q, user); - private int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId, - int userId) { - try { - return mService.getShortcutIconResId(mContext.getPackageName(), - packageName, shortcutId, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0; } /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 39bc783b53ac..ade22482bbc9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4972,6 +4972,27 @@ public abstract class PackageManager { IPackageDataObserver observer); /** + * Attempts to delete the cache files associated with an application for a given user. Since + * this may take a little while, the result will be posted back to the given observer. A + * deletion will fail if the calling context lacks the + * {@link android.Manifest.permission#DELETE_CACHE_FILES} permission, if the named package + * cannot be found, or if the named package is a "system package". If {@code userId} does not + * belong to the calling user, the caller must have + * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission. + * + * @param packageName The name of the package to delete + * @param userId the user for which the cache files needs to be deleted + * @param observer An observer callback to get notified when the cache file deletion is + * complete. + * {@link android.content.pm.IPackageDataObserver#onRemoveCompleted(String, boolean)} + * will be called when that happens. observer may be null to indicate that no + * callback is desired. + * @hide + */ + public abstract void deleteApplicationCacheFilesAsUser(String packageName, int userId, + IPackageDataObserver observer); + + /** * Free storage by deleting LRU sorted list of cache files across * all applications. If the currently available free storage * on the device is greater than or equal to the requested diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 7a807c4cf949..a9000155bc00 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -34,6 +34,8 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; // TODO Enhance javadoc /** @@ -107,6 +109,11 @@ public final class ShortcutInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface CloneFlags {} + /** + * Shortcut category for + */ + public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; + private final String mId; @NonNull @@ -124,6 +131,9 @@ public final class ShortcutInfo implements Parcelable { @Nullable private String mText; + @NonNull + private List<String> mCategories; + /** * Intent *with extras removed*. */ @@ -168,6 +178,7 @@ public final class ShortcutInfo implements Parcelable { mIcon = b.mIcon; mTitle = b.mTitle; mText = b.mText; + mCategories = clone(b.mCategories); mIntent = b.mIntent; if (mIntent != null) { final Bundle intentExtras = mIntent.getExtras(); @@ -181,6 +192,10 @@ public final class ShortcutInfo implements Parcelable { updateTimestamp(); } + private <T> ArrayList<T> clone(List<T> source) { + return (source == null) ? null : new ArrayList<>(source); + } + /** * Throws if any of the mandatory fields is not set. * @@ -202,17 +217,20 @@ public final class ShortcutInfo implements Parcelable { mFlags = source.mFlags; mLastChangedTimestamp = source.mLastChangedTimestamp; + // Just always keep it since it's cheep. + mIconResourceId = source.mIconResourceId; + if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) { mActivityComponent = source.mActivityComponent; if ((cloneFlags & CLONE_REMOVE_ICON) == 0) { mIcon = source.mIcon; mBitmapPath = source.mBitmapPath; - mIconResourceId = source.mIconResourceId; } mTitle = source.mTitle; mText = source.mText; + mCategories = clone(source.mCategories); if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) { mIntent = source.mIntent; mIntentPersistableExtras = source.mIntentPersistableExtras; @@ -262,6 +280,9 @@ public final class ShortcutInfo implements Parcelable { if (source.mText != null) { mText = source.mText; } + if (source.mCategories != null) { + mCategories = clone(source.mCategories); + } if (source.mIntent != null) { mIntent = source.mIntent; mIntentPersistableExtras = source.mIntentPersistableExtras; @@ -325,6 +346,8 @@ public final class ShortcutInfo implements Parcelable { private String mText; + private List<String> mCategories; + private Intent mIntent; private int mWeight; @@ -369,8 +392,9 @@ public final class ShortcutInfo implements Parcelable { * * <p>For performance reasons, icons will <b>NOT</b> be available on instances * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications - * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo)} - * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo)}. + * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true. + * Otherwise, if {@link #hasIconFile()} is true, use + * {@link LauncherApps#getShortcutIconFd} to load the image. */ @NonNull public Builder setIcon(Icon icon) { @@ -403,6 +427,18 @@ public final class ShortcutInfo implements Parcelable { } /** + * Sets categories for a shortcut. Launcher applications may use this information to + * categorise shortcuts. + * + * @see #SHORTCUT_CATEGORY_CONVERSATION + */ + @NonNull + public Builder setCategories(List<String> categories) { + mCategories = categories; + return this; + } + + /** * Sets the intent of a shortcut. This is a mandatory field. The extras must only contain * persistable information. (See {@link PersistableBundle}). */ @@ -500,6 +536,14 @@ public final class ShortcutInfo implements Parcelable { } /** + * Return the categories. + */ + @Nullable + public List<String> getCategories() { + return mCategories; + } + + /** * Return the intent. * * <p>All shortcuts must have an intent, but this method will return null when @@ -662,7 +706,9 @@ public final class ShortcutInfo implements Parcelable { mIconResourceId = iconResourceId; } - /** @hide */ + /** + * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true. + */ public int getIconResourceId() { return mIconResourceId; } @@ -687,6 +733,8 @@ public final class ShortcutInfo implements Parcelable { mIcon = source.readParcelable(cl); mTitle = source.readString(); mText = source.readString(); + mCategories = new ArrayList<>(); + source.readStringList(mCategories); mIntent = source.readParcelable(cl); mIntentPersistableExtras = source.readParcelable(cl); mWeight = source.readInt(); @@ -706,6 +754,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeParcelable(mIcon, flags); dest.writeString(mTitle); dest.writeString(mText); + dest.writeStringList(mCategories); dest.writeParcelable(mIntent, flags); dest.writeParcelable(mIntentPersistableExtras, flags); dest.writeInt(mWeight); @@ -770,6 +819,9 @@ public final class ShortcutInfo implements Parcelable { sb.append(", text="); sb.append(secure ? "***" : mText); + sb.append(", categories="); + sb.append(mCategories); + sb.append(", icon="); sb.append(mIcon); @@ -807,7 +859,7 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public ShortcutInfo( @UserIdInt int userId, String id, String packageName, ComponentName activityComponent, - Icon icon, String title, String text, Intent intent, + Icon icon, String title, String text, List<String> categories, Intent intent, PersistableBundle intentPersistableExtras, int weight, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String bitmapPath) { @@ -818,6 +870,7 @@ public final class ShortcutInfo implements Parcelable { mIcon = icon; mTitle = title; mText = text; + mCategories = clone(categories); mIntent = intent; mIntentPersistableExtras = intentPersistableExtras; mWeight = weight; diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index 919ccda91ba9..75803d3631a3 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -34,11 +34,11 @@ import java.util.List; * <h3>Dynamic shortcuts and pinned shortcuts</h3> * * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and - * {@link #addDynamicShortcut(ShortcutInfo)}. There can be at most + * {@link #addDynamicShortcuts(List)}. There can be at most * {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same * application. - * A dynamic shortcut can be deleted with {@link #deleteDynamicShortcut(String)}, and apps - * can also use {@link #deleteAllDynamicShortcuts()} to delete all dynamic shortcuts. + * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps + * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts. * * <p>The shortcuts that are currently published by the above APIs are called "dynamic", because * they can be removed by the creator application at any time. The user may "pin" dynamic shortcuts @@ -61,11 +61,11 @@ import java.util.List; * * <h3>Rate limiting</h3> * - * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)}, + * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, * and {@link #updateShortcuts(List)} will be * rate-limited. An application can call these methods at most * {@link #getRemainingCallCount()} times until the rate-limiting counter is reset, - * which happens at a certain time every day. + * which happens every hour. * * <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time. * @@ -153,10 +153,10 @@ public class ShortcutManager { * @throws IllegalArgumentException if the caller application has already published the * max number of dynamic shortcuts. */ - public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) { + public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { try { - return mService.addDynamicShortcut( - mContext.getPackageName(), shortcutInfo, injectMyUserId()); + return mService.addDynamicShortcuts(mContext.getPackageName(), + new ParceledListSlice(shortcutInfoList), injectMyUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -165,9 +165,10 @@ public class ShortcutManager { /** * Delete a single dynamic shortcut by ID. */ - public void deleteDynamicShortcut(@NonNull String shortcutId) { + public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) { try { - mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId()); + mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds, + injectMyUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -176,9 +177,9 @@ public class ShortcutManager { /** * Delete all dynamic shortcuts from the caller application. */ - public void deleteAllDynamicShortcuts() { + public void removeAllDynamicShortcuts() { try { - mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId()); + mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 18a155d78707..b5423392b96e 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -501,11 +501,8 @@ public class CameraDeviceImpl extends CameraDevice Log.d(TAG, "createCaptureSessionByOutputConfiguration"); } - // OutputConfiguration objects aren't immutable, make a copy before using. - List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>(); - for (OutputConfiguration output : outputConfigurations) { - currentOutputs.add(new OutputConfiguration(output)); - } + // OutputConfiguration objects are immutable, but need to have our own array + List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations); createCaptureSessionInternal(null, currentOutputs, callback, handler, /*isConstrainedHighSpeed*/false); diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index cd0c4742d2cc..61b534bf22de 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -17,6 +17,8 @@ package android.hardware.camera2.params; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.utils.HashCodeHelpers; @@ -71,12 +73,12 @@ public final class OutputConfiguration implements Parcelable { public static final int ROTATION_270 = 3; /** - * Invalid surface set ID. + * Invalid surface group ID. * *<p>An {@link OutputConfiguration} with this value indicates that the included surface - *doesn't belong to any surface set.</p> + *doesn't belong to any surface group.</p> */ - public static final int SURFACE_SET_ID_INVALID = -1; + public static final int SURFACE_GROUP_ID_NONE = -1; /** * Create a new {@link OutputConfiguration} instance with a {@link Surface}. @@ -84,11 +86,47 @@ public final class OutputConfiguration implements Parcelable { * @param surface * A Surface for camera to output to. * - * <p>This constructor creates a default configuration.</p> + * <p>This constructor creates a default configuration, with a surface group ID of + * {@value #SURFACE_GROUP_ID_NONE}.</p> * */ - public OutputConfiguration(Surface surface) { - this(surface, ROTATION_0); + public OutputConfiguration(@NonNull Surface surface) { + this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0); + } + + /** + * Create a new {@link OutputConfiguration} instance with a {@link Surface}, + * with a surface group ID. + * + * <p> + * A surface group ID is used to identify which surface group this output surface belongs to. A + * surface group is a group of output surfaces that are not intended to receive camera output + * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used + * by all the surfaces from the same surface group, therefore may reduce the overall memory + * footprint. The application should only set the same set ID for the streams that are not + * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any + * surface group. The default value is {@value #SURFACE_GROUP_ID_NONE}.</p> + * + * <p>For example, a video chat application that has an adaptive output resolution feature would + * need two (or more) output resolutions, to switch resolutions without any output glitches. + * However, at any given time, only one output is active to minimize outgoing network bandwidth + * and encoding overhead. To save memory, the application should set the video outputs to have + * the same non-negative group ID, so that the camera device can share the same memory region + * for the alternating outputs.</p> + * + * <p>It is not an error to include output streams with the same group ID in the same capture + * request, but the resulting memory consumption may be higher than if the two streams were + * not in the same surface group to begin with, especially if the outputs have substantially + * different dimensions.</p> + * + * @param surfaceGroupId + * A group ID for this output, used for sharing memory between multiple outputs. + * @param surface + * A Surface for camera to output to. + * + */ + public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface) { + this(surfaceGroupId, surface, ROTATION_0); } /** @@ -100,9 +138,36 @@ public final class OutputConfiguration implements Parcelable { * A Surface for camera to output to. * @param rotation * The desired rotation to be applied on camera output. Value must be one of - * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degree, + * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees, + * application should make sure corresponding surface size has width and height + * transposed relative to the width and height without rotation. For example, + * if application needs camera to capture 1280x720 picture and rotate it by 90 degree, + * application should set rotation to {@code ROTATION_90} and make sure the + * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might + * throw {@code IllegalArgumentException} if device cannot perform such rotation. + * @hide + */ + @SystemApi + public OutputConfiguration(@NonNull Surface surface, int rotation) { + this(SURFACE_GROUP_ID_NONE, surface, rotation); + } + + + /** + * Create a new {@link OutputConfiguration} instance, with rotation and a group ID. + * + * <p>This constructor takes an argument for desired camera rotation and for the surface group + * ID. See {@link #OutputConfiguration(int, Surface)} for details of the group ID.</p> + * + * @param surfaceGroupId + * A group ID for this output, used for sharing memory between multiple outputs. + * @param surface + * A Surface for camera to output to. + * @param rotation + * The desired rotation to be applied on camera output. Value must be one of + * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees, * application should make sure corresponding surface size has width and height - * transposed corresponding to the width and height without rotation. For example, + * transposed relative to the width and height without rotation. For example, * if application needs camera to capture 1280x720 picture and rotate it by 90 degree, * application should set rotation to {@code ROTATION_90} and make sure the * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might @@ -110,15 +175,16 @@ public final class OutputConfiguration implements Parcelable { * @hide */ @SystemApi - public OutputConfiguration(Surface surface, int rotation) { + public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) { checkNotNull(surface, "Surface must not be null"); checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); - mSurfaceSetId = SURFACE_SET_ID_INVALID; + mSurfaceGroupId = surfaceGroupId; mSurface = surface; mRotation = rotation; mConfiguredSize = SurfaceUtils.getSurfaceSize(surface); mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface); mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface); + mConfiguredGenerationId = surface.getGenerationId(); } /** @@ -129,35 +195,36 @@ public final class OutputConfiguration implements Parcelable { * * @hide */ - @SystemApi - public OutputConfiguration(OutputConfiguration other) { + public OutputConfiguration(@NonNull OutputConfiguration other) { if (other == null) { throw new IllegalArgumentException("OutputConfiguration shouldn't be null"); } this.mSurface = other.mSurface; this.mRotation = other.mRotation; - this.mSurfaceSetId = other.mSurfaceSetId; + this.mSurfaceGroupId = other.mSurfaceGroupId; this.mConfiguredDataspace = other.mConfiguredDataspace; this.mConfiguredFormat = other.mConfiguredFormat; this.mConfiguredSize = other.mConfiguredSize; + this.mConfiguredGenerationId = other.mConfiguredGenerationId; } /** * Create an OutputConfiguration from Parcel. */ - private OutputConfiguration(Parcel source) { + private OutputConfiguration(@NonNull Parcel source) { int rotation = source.readInt(); int surfaceSetId = source.readInt(); Surface surface = Surface.CREATOR.createFromParcel(source); checkNotNull(surface, "Surface must not be null"); checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); - mSurfaceSetId = surfaceSetId; + mSurfaceGroupId = surfaceSetId; mSurface = surface; mRotation = rotation; mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface); mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface); mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface); + mConfiguredGenerationId = mSurface.getGenerationId(); } /** @@ -165,6 +232,7 @@ public final class OutputConfiguration implements Parcelable { * * @return the {@link Surface} associated with this {@link OutputConfiguration}. */ + @NonNull public Surface getSurface() { return mSurface; } @@ -183,35 +251,13 @@ public final class OutputConfiguration implements Parcelable { } /** - * Set the surface set ID to this {@link OutputConfiguration}. + * Get the surface group ID associated with this {@link OutputConfiguration}. * - * <p> - * A surface set ID is used to identify which surface set this output surface belongs to. A - * surface set is a group of output surfaces that are not intended to receive camera output - * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used - * by all the surfaces from the same surface set, therefore may save the overall memory - * footprint. The application should only set the same set ID for the streams that are not - * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any - * surface set. The default value will be {@value #SURFACE_SET_ID_INVALID}. - * </p> - * - * @param setId - */ - public void setSurfaceSetId(int setId) { - if (setId < 0) { - setId = SURFACE_SET_ID_INVALID; - } - mSurfaceSetId = setId; - } - - /** - * Get the surface set Id associated with this {@link OutputConfiguration}. - * - * @return the surface set Id associated with this {@link OutputConfiguration}. - * Value will be one of ROTATION_[0, 90, 180, 270] + * @return the surface group ID associated with this {@link OutputConfiguration}. + * The default value is {@value #SURFACE_GROUP_ID_NONE}. */ - public int getSurfaceSetId() { - return mSurfaceSetId; + public int getSurfaceGroupId() { + return mSurfaceGroupId; } public static final Parcelable.Creator<OutputConfiguration> CREATOR = @@ -244,7 +290,7 @@ public final class OutputConfiguration implements Parcelable { throw new IllegalArgumentException("dest must not be null"); } dest.writeInt(mRotation); - dest.writeInt(mSurfaceSetId); + dest.writeInt(mSurfaceGroupId); mSurface.writeToParcel(dest, flags); } @@ -265,12 +311,13 @@ public final class OutputConfiguration implements Parcelable { return true; } else if (obj instanceof OutputConfiguration) { final OutputConfiguration other = (OutputConfiguration) obj; - return mSurface == other.mSurface && - mRotation == other.mRotation && + return mRotation == other.mRotation && + mSurface == other.mSurface && + mConfiguredGenerationId == other.mConfiguredGenerationId && mConfiguredSize.equals(other.mConfiguredSize) && mConfiguredFormat == other.mConfiguredFormat && mConfiguredDataspace == other.mConfiguredDataspace && - mSurfaceSetId == other.mSurfaceSetId; + mSurfaceGroupId == other.mSurfaceGroupId; } return false; } @@ -280,16 +327,20 @@ public final class OutputConfiguration implements Parcelable { */ @Override public int hashCode() { - return HashCodeHelpers.hashCode(mSurface.hashCode(), mRotation); + return HashCodeHelpers.hashCode( + mRotation, mSurface.hashCode(), mConfiguredGenerationId, + mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId); } private static final String TAG = "OutputConfiguration"; private final Surface mSurface; private final int mRotation; - private int mSurfaceSetId; + private int mSurfaceGroupId; // The size, format, and dataspace of the surface when OutputConfiguration is created. private final Size mConfiguredSize; private final int mConfiguredFormat; private final int mConfiguredDataspace; + // Surface generation ID to distinguish changes to Surface native internals + private final int mConfiguredGenerationId; } diff --git a/core/java/android/inputmethodservice/CompactExtractEditLayout.java b/core/java/android/inputmethodservice/CompactExtractEditLayout.java new file mode 100644 index 000000000000..35c54b284275 --- /dev/null +++ b/core/java/android/inputmethodservice/CompactExtractEditLayout.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package android.inputmethodservice; + +import android.content.Context; +import android.content.res.Resources; +import android.annotation.FractionRes; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +/** + * A special purpose layout for the editor extract view for tiny (sub 250dp) screens. + * The layout is based on sizes proportional to screen pixel size to provide for the + * best layout fidelity on varying pixel sizes and densities. + * + * @hide + */ +public class CompactExtractEditLayout extends LinearLayout { + private View mInputExtractEditText; + private View mInputExtractAccessories; + private View mInputExtractAction; + private boolean mPerformLayoutChanges; + + public CompactExtractEditLayout(Context context) { + super(context); + } + + public CompactExtractEditLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CompactExtractEditLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mInputExtractEditText = findViewById(com.android.internal.R.id.inputExtractEditText); + mInputExtractAccessories = findViewById(com.android.internal.R.id.inputExtractAccessories); + mInputExtractAction = findViewById(com.android.internal.R.id.inputExtractAction); + + if (mInputExtractEditText != null && mInputExtractAccessories != null + && mInputExtractAction != null) { + mPerformLayoutChanges = true; + } + } + + private int applyFractionInt(@FractionRes int fraction, int whole) { + return Math.round(getResources().getFraction(fraction, whole, whole)); + } + + private static void setLayoutHeight(View v, int px) { + ViewGroup.LayoutParams lp = v.getLayoutParams(); + lp.height = px; + v.setLayoutParams(lp); + } + + private static void setLayoutMarginBottom(View v, int px) { + ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); + lp.bottomMargin = px; + v.setLayoutParams(lp); + } + + private void applyProportionalLayout(int screenWidthPx, int screenHeightPx) { + if (getResources().getConfiguration().isScreenRound()) { + setGravity(Gravity.BOTTOM); + } + setLayoutHeight(this, applyFractionInt( + com.android.internal.R.fraction.input_extract_layout_height, screenHeightPx)); + + setPadding( + applyFractionInt(com.android.internal.R.fraction.input_extract_layout_padding_left, + screenWidthPx), + 0, + applyFractionInt(com.android.internal.R.fraction.input_extract_layout_padding_right, + screenWidthPx), + 0); + + setLayoutMarginBottom(mInputExtractEditText, + applyFractionInt(com.android.internal.R.fraction.input_extract_text_margin_bottom, + screenHeightPx)); + + setLayoutMarginBottom(mInputExtractAccessories, + applyFractionInt(com.android.internal.R.fraction.input_extract_action_margin_bottom, + screenHeightPx)); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mPerformLayoutChanges) { + Resources res = getResources(); + DisplayMetrics dm = res.getDisplayMetrics(); + int heightPixels = dm.heightPixels; + int widthPixels = dm.widthPixels; + applyProportionalLayout(widthPixels, heightPixels); + } + } +} diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index cc201bc78bb5..085b97cc0f6d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -68,9 +68,10 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; -import android.widget.Button; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.LinearLayout; +import android.widget.TextView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -302,7 +303,7 @@ public class InputMethodService extends AbstractInputMethodService { boolean mExtractViewHidden; ExtractEditText mExtractEditText; ViewGroup mExtractAccessories; - Button mExtractAction; + View mExtractAction; ExtractedText mExtractedText; int mExtractedToken; @@ -1344,7 +1345,7 @@ public class InputMethodService extends AbstractInputMethodService { mExtractEditText = (ExtractEditText)view.findViewById( com.android.internal.R.id.inputExtractEditText); mExtractEditText.setIME(this); - mExtractAction = (Button)view.findViewById( + mExtractAction = view.findViewById( com.android.internal.R.id.inputExtractAction); if (mExtractAction != null) { mExtractAccessories = (ViewGroup)view.findViewById( @@ -2408,7 +2409,35 @@ public class InputMethodService extends AbstractInputMethodService { return getText(com.android.internal.R.string.ime_action_default); } } - + + /** + * Return a drawable resource id that can be used as a button icon for the given + * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. + * + * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}. + * + * @return Returns a drawable resource id to use. + */ + @DrawableRes + private int getIconForImeAction(int imeOptions) { + switch (imeOptions&EditorInfo.IME_MASK_ACTION) { + case EditorInfo.IME_ACTION_GO: + return com.android.internal.R.drawable.ic_input_extract_action_go; + case EditorInfo.IME_ACTION_SEARCH: + return com.android.internal.R.drawable.ic_input_extract_action_search; + case EditorInfo.IME_ACTION_SEND: + return com.android.internal.R.drawable.ic_input_extract_action_send; + case EditorInfo.IME_ACTION_NEXT: + return com.android.internal.R.drawable.ic_input_extract_action_next; + case EditorInfo.IME_ACTION_DONE: + return com.android.internal.R.drawable.ic_input_extract_action_done; + case EditorInfo.IME_ACTION_PREVIOUS: + return com.android.internal.R.drawable.ic_input_extract_action_previous; + default: + return com.android.internal.R.drawable.ic_input_extract_action_return; + } + } + /** * Called when the fullscreen-mode extracting editor info has changed, * to determine whether the extracting (extract text and candidates) portion @@ -2459,10 +2488,20 @@ public class InputMethodService extends AbstractInputMethodService { if (hasAction) { mExtractAccessories.setVisibility(View.VISIBLE); if (mExtractAction != null) { - if (ei.actionLabel != null) { - mExtractAction.setText(ei.actionLabel); + if (mExtractAction instanceof ImageButton) { + ((ImageButton) mExtractAction) + .setImageResource(getIconForImeAction(ei.imeOptions)); + if (ei.actionLabel != null) { + mExtractAction.setContentDescription(ei.actionLabel); + } else { + mExtractAction.setContentDescription(getTextForImeAction(ei.imeOptions)); + } } else { - mExtractAction.setText(getTextForImeAction(ei.imeOptions)); + if (ei.actionLabel != null) { + ((TextView) mExtractAction).setText(ei.actionLabel); + } else { + ((TextView) mExtractAction).setText(getTextForImeAction(ei.imeOptions)); + } } mExtractAction.setOnClickListener(mActionClickListener); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a02533792245..5d008e3c8db1 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2734,7 +2734,7 @@ public class ConnectivityManager { private void incCallbackHandlerRefCount() { synchronized(sCallbackRefCount) { if (sCallbackRefCount.incrementAndGet() == 1) { - // TODO - switch this over to a ManagerThread or expire it when done + // TODO: switch this to ConnectivityThread HandlerThread callbackThread = new HandlerThread("ConnectivityManager"); callbackThread.start(); sCallbackHandler = new CallbackHandler(callbackThread.getLooper(), @@ -3093,6 +3093,10 @@ public class ConnectivityManager { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + + synchronized (sNetworkCallback) { + sNetworkCallback.remove(networkCallback.networkRequest); + } } /** diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 20c216826531..2dacf8f460bb 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -120,12 +120,17 @@ public abstract class NetworkAgent extends Handler { * either a bad network configuration (no internet link) or captive portal. * * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} + * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} + * representing URL that Internet probe was redirect to, if it was redirected, + * or mapping to {@code null} otherwise. */ public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; public static final int VALID_NETWORK = 1; public static final int INVALID_NETWORK = 2; + public static String REDIRECT_URL_KEY = "redirect URL"; + /** * Sent by the NetworkAgent to ConnectivityService to indicate this network was * explicitly selected. This should be sent before the NetworkInfo is marked @@ -283,11 +288,12 @@ public abstract class NetworkAgent extends Handler { break; } case CMD_REPORT_NETWORK_STATUS: { + String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY); if (VDBG) { log("CMD_REPORT_NETWORK_STATUS(" + - (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)")); + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl); } - networkStatus(msg.arg1); + networkStatus(msg.arg1, redirectUrl); break; } case CMD_SAVE_ACCEPT_UNVALIDATED: { @@ -443,8 +449,12 @@ public abstract class NetworkAgent extends Handler { * * This may be called multiple times as the network status changes and may * generate false negatives if we lose ip connectivity before the link is torn down. + * + * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}. + * @param redirectUrl If the Internet probe was redirected, this is the destination it was + * redirected to, otherwise {@code null}. */ - protected void networkStatus(int status) { + protected void networkStatus(int status, String redirectUrl) { } /** diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index cfd0468a6e27..1ac9fca51b77 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -228,7 +228,6 @@ public class TrafficStats { * statistics parameters. * * @see #setThreadStatsTag(int) - * @see #setThreadStatsUid(int) */ public static void tagSocket(Socket socket) throws SocketException { SocketTagger.get().tag(socket); @@ -249,7 +248,6 @@ public class TrafficStats { * parameters. * * @see #setThreadStatsTag(int) - * @see #setThreadStatsUid(int) */ public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { SocketTagger.get().tag(socket); diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index 67293475a9e7..87a0b709d9f8 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -44,6 +44,7 @@ public class X509TrustManagerExtensions { private final X509TrustManager mTrustManager; private final Method mCheckServerTrusted; private final Method mIsUserAddedCertificate; + private final Method mIsSameTrustConfiguration; /** * Constructs a new X509TrustManagerExtensions wrapper. @@ -57,6 +58,7 @@ public class X509TrustManagerExtensions { mTrustManager = null; mCheckServerTrusted = null; mIsUserAddedCertificate = null; + mIsSameTrustConfiguration = null; return; } // Use duck typing if possible. @@ -80,6 +82,15 @@ public class X509TrustManagerExtensions { throw new IllegalArgumentException( "Required method isUserAddedCertificate(X509Certificate) missing"); } + // Get the option isSameTrustConfiguration method. + Method isSameTrustConfiguration = null; + try { + isSameTrustConfiguration = tm.getClass().getMethod("isSameTrustConfiguration", + String.class, + String.class); + } catch (ReflectiveOperationException ignored) { + } + mIsSameTrustConfiguration = isSameTrustConfiguration; } /** @@ -150,6 +161,19 @@ public class X509TrustManagerExtensions { */ @SystemApi public boolean isSameTrustConfiguration(String hostname1, String hostname2) { - return true; + if (mIsSameTrustConfiguration == null) { + return true; + } + try { + return (Boolean) mIsSameTrustConfiguration.invoke(mTrustManager, hostname1, hostname2); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to call isSameTrustConfiguration", e); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } else { + throw new RuntimeException("isSameTrustConfiguration failed", e.getCause()); + } + } } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index c4528372987f..773e7dd601c8 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -3094,14 +3094,8 @@ public abstract class BatteryStats implements Parcelable { dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA, u.getWifiControllerActivity(), which); - // Dump Bluetooth scan data, per UID. - final long bleScanTimeUs = u.getBluetoothScanTimer().getTotalTimeLocked( + dumpTimer(pw, uid, category, BLUETOOTH_MISC_DATA, u.getBluetoothScanTimer(), rawRealtime, which); - final int bleScanCount = u.getBluetoothScanTimer().getCountLocked(which); - if (bleScanTimeUs != 0 || bleScanCount != 0) { - dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA, - bleScanTimeUs / 1000, bleScanCount); - } dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA, u.getBluetoothControllerActivity(), which); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index ece12280bb80..0a8fdd9fac3b 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -824,7 +824,9 @@ public class StorageManager { } } - /** {@hide} */ + /** + * Return the {@link StorageVolume} that contains the given file, or {@code null} if none. + */ public @Nullable StorageVolume getStorageVolume(File file) { return getStorageVolume(getVolumeList(), file); } @@ -836,9 +838,13 @@ public class StorageManager { /** {@hide} */ private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) { + if (file == null) { + return null; + } try { file = file.getCanonicalFile(); } catch (IOException ignored) { + Slog.d(TAG, "Could not get canonical path for " + file); return null; } for (StorageVolume volume : volumes) { @@ -1056,8 +1062,8 @@ public class StorageManager { } /** - * Return if data stored at the given path will be encrypted while at rest. - * This can help apps avoid the overhead of double-encrypting data. + * Return if data stored at or under the given path will be encrypted while + * at rest. This can help apps avoid the overhead of double-encrypting data. */ public boolean isEncrypted(File file) { if (FileUtils.contains(Environment.getDataDirectory(), file)) { diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 89ac27c9a816..de19f819295b 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -283,7 +283,7 @@ public final class MediaStore { * * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above * and declares as using the {@link android.Manifest.permission#CAMERA} permission which - * is not granted, then atempting to use this action will result in a {@link + * is not granted, then attempting to use this action will result in a {@link * java.lang.SecurityException}. * * @see #EXTRA_OUTPUT diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 638be5167f86..788a20c3745f 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -296,7 +296,8 @@ public final class Settings { * monitoring of encrypted network traffic. * <p> * In some cases, a matching Activity may not exist, so ensure you - * safeguard against this. + * safeguard against this. Add {@link #EXTRA_NUMBER_OF_CERTIFICATES} extra to indicate the + * number of certificates. * <p> * Input: Nothing. * <p> @@ -1369,6 +1370,16 @@ public final class Settings { public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes"; + /** + * Activity Extra: Number of certificates + * <p> + * This can be passed as an extra field to the {@link #ACTION_MONITORING_CERT_INFO} + * intent to indicate the number of certificates + * @hide + */ + public static final String EXTRA_NUMBER_OF_CERTIFICATES = + "android.settings.extra.number_of_certificates"; + private static final String JID_RESOURCE_PREFIX = "android"; public static final String AUTHORITY = "settings"; @@ -1581,6 +1592,8 @@ public final class Settings { public static final class System extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version"; + private static final float DEFAULT_FONT_SCALE = 1.0f; + /** @hide */ public static interface Validator { public boolean validate(String value); @@ -2089,9 +2102,9 @@ public final class Settings { public static void getConfigurationForUser(ContentResolver cr, Configuration outConfig, int userHandle) { outConfig.fontScale = Settings.System.getFloatForUser( - cr, FONT_SCALE, outConfig.fontScale, userHandle); + cr, FONT_SCALE, DEFAULT_FONT_SCALE, userHandle); if (outConfig.fontScale < 0) { - outConfig.fontScale = 1; + outConfig.fontScale = DEFAULT_FONT_SCALE; } outConfig.setLocales(LocaleList.forLanguageTags( Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle))); @@ -7793,13 +7806,13 @@ public final class Settings { * ShortcutManager specific settings. * This is encoded as a key=value list, separated by commas. Ex: * - * "reset_interval_sec=86400,max_daily_updates=5" + * "reset_interval_sec=86400,max_updates_per_interval=1" * * The following keys are supported: * * <pre> * reset_interval_sec (long) - * max_daily_updates (int) + * max_updates_per_interval (int) * max_icon_dimension_dp (int, DP) * max_icon_dimension_dp_lowram (int, DP) * max_shortcuts (int) diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java index 19f688787abe..859e022952db 100644 --- a/core/java/android/security/net/config/RootTrustManager.java +++ b/core/java/android/security/net/config/RootTrustManager.java @@ -148,4 +148,15 @@ public class RootTrustManager extends X509ExtendedTrustManager { NetworkSecurityConfig config = mConfig.getConfigForHostname(""); return config.getTrustManager().getAcceptedIssuers(); } + + /** + * Returns {@code true} if this trust manager uses the same trust configuration for the provided + * hostnames. + * + * <p>This is required by android.net.http.X509TrustManagerExtensions. + */ + public boolean isSameTrustConfiguration(String hostname1, String hostname2) { + return mConfig.getConfigForHostname(hostname1) + .equals(mConfig.getConfigForHostname(hostname2)); + } } diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index 3564e11f5b13..e93e58da20d6 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -48,6 +48,9 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener implements KeyListener { /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete(); + private static final int LINE_FEED = 0x0A; + private static final int CARRIAGE_RETURN = 0x0D; + private final Object mLock = new Object(); @GuardedBy("mLock") @@ -110,34 +113,37 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener // Initial state final int STATE_START = 0; + // The offset is immediately before line feed. + final int STATE_LF = 1; + // The offset is immediately before a KEYCAP. - final int STATE_BEFORE_KEYCAP = 1; + final int STATE_BEFORE_KEYCAP = 2; // The offset is immediately before a variation selector and a KEYCAP. - final int STATE_BEFORE_VS_AND_KEYCAP = 2; + final int STATE_BEFORE_VS_AND_KEYCAP = 3; // The offset is immediately before an emoji modifier. - final int STATE_BEFORE_EMOJI_MODIFIER = 3; + final int STATE_BEFORE_EMOJI_MODIFIER = 4; // The offset is immediately before a variation selector and an emoji modifier. - final int STATE_BEFORE_VS_AND_EMOJI_MODIFIER = 4; + final int STATE_BEFORE_VS_AND_EMOJI_MODIFIER = 5; // The offset is immediately before a variation selector. - final int STATE_BEFORE_VS = 5; + final int STATE_BEFORE_VS = 6; // The offset is immediately before a ZWJ emoji. - final int STATE_BEFORE_ZWJ_EMOJI = 6; + final int STATE_BEFORE_ZWJ_EMOJI = 7; // The offset is immediately before a ZWJ that were seen before a ZWJ emoji. - final int STATE_BEFORE_ZWJ = 7; + final int STATE_BEFORE_ZWJ = 8; // The offset is immediately before a variation selector and a ZWJ that were seen before a // ZWJ emoji. - final int STATE_BEFORE_VS_AND_ZWJ = 8; + final int STATE_BEFORE_VS_AND_ZWJ = 9; // The number of following RIS code points is odd. - final int STATE_ODD_NUMBERED_RIS = 9; + final int STATE_ODD_NUMBERED_RIS = 10; // The number of following RIS code points is even. - final int STATE_EVEN_NUMBERED_RIS = 10; + final int STATE_EVEN_NUMBERED_RIS = 11; // The state machine has been stopped. - final int STATE_FINISHED = 11; + final int STATE_FINISHED = 12; int deleteCharCount = 0; // Char count to be deleted by backspace. int lastSeenVSCharCount = 0; // Char count of previous variation selector. @@ -152,7 +158,9 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener switch (state) { case STATE_START: deleteCharCount = Character.charCount(codePoint); - if (isVariationSelector(codePoint)) { + if (codePoint == LINE_FEED) { + state = STATE_LF; + } else if (isVariationSelector(codePoint)) { state = STATE_BEFORE_VS; } else if (Emoji.isZwjEmoji(codePoint)) { state = STATE_BEFORE_ZWJ_EMOJI; @@ -166,6 +174,11 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener state = STATE_FINISHED; } break; + case STATE_LF: + if (codePoint == CARRIAGE_RETURN) { + ++deleteCharCount; + } + state = STATE_FINISHED; case STATE_ODD_NUMBERED_RIS: if (Emoji.isRegionalIndicatorSymbol(codePoint)) { deleteCharCount += 2; /* Char count of RIS */ diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl index cbc8dbdd1726..88ac27118406 100644 --- a/core/java/android/view/IDockedStackListener.aidl +++ b/core/java/android/view/IDockedStackListener.aidl @@ -42,4 +42,9 @@ oneway interface IDockedStackListener { * @param animDuration The duration of the animation for changing the minimized state. */ void onDockedStackMinimizedChanged(boolean minimized, long animDuration); + + /** + * Called when window manager repositioned the docked stack after a screen rotation change. + */ + void onDockSideChanged(int newDockSide); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index c97247656540..c4ed94f6184d 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -893,6 +893,10 @@ public final class ThreadedRenderer { nSerializeDisplayListTree(mNativeProxy); } + public static boolean copySurfaceInto(Surface surface, Bitmap bitmap) { + return nCopySurfaceInto(surface, bitmap); + } + @Override protected void finalize() throws Throwable { try { @@ -1029,4 +1033,6 @@ public final class ThreadedRenderer { private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer); private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver); + + private static native boolean nCopySurfaceInto(Surface surface, Bitmap bitmap); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 7e5109637855..307e700e3655 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10278,7 +10278,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @Visibility boolean dispatchVisibilityAggregated(boolean isVisible) { final boolean thisVisible = getVisibility() == VISIBLE; - if (thisVisible) { + // If we're not visible but something is telling us we are, ignore it. + if (thisVisible || !isVisible) { onVisibilityAggregated(isVisible); } return thisVisible && isVisible; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a324767ac4ed..44b92e18144e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3373,6 +3373,16 @@ public final class ViewRootImpl implements ViewParent, } @Override + public boolean sendMessageAtTime(Message msg, long uptimeMillis) { + if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) { + // Debugging for b/27963013 + throw new NullPointerException( + "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:"); + } + return super.sendMessageAtTime(msg, uptimeMillis); + } + + @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_INVALIDATE: diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index dc433b11f91d..dc4db01e4dd2 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -20,6 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.res.Configuration; +import android.icu.text.DisplayContext; +import android.icu.text.LocaleDisplayNames; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -421,39 +424,97 @@ public final class InputMethodSubtype implements Parcelable { } /** - * @param context Context will be used for getting Locale and PackageManager. - * @param packageName The package name of the IME - * @param appInfo The application info of the IME - * @return a display name for this subtype. The string resource of the label (mSubtypeNameResId) - * may have exactly one %s in it. If there is, the %s part will be replaced with the locale's - * display name by the formatter. If there is not, this method returns the string specified by - * mSubtypeNameResId. If mSubtypeNameResId is not specified (== 0), it's up to the framework to - * generate an appropriate display name. + * Returns a display name for this subtype. + * + * <p>If {@code subtypeNameResId} is specified (!= 0) text generated from that resource will + * be returned. The localized string resource of the label should be capitalized for inclusion + * in UI lists. The string resource may contain at most one {@code %s}. If present, the + * {@code %s} will be replaced with the display name of the subtype locale in the user's locale. + * + * <p>If {@code subtypeNameResId} is not specified (== 0) the framework returns the display name + * of the subtype locale, as capitalized for use in UI lists, in the user's locale. + * + * @param context {@link Context} will be used for getting {@link Locale} and + * {@link android.content.pm.PackageManager}. + * @param packageName The package name of the input method. + * @param appInfo The {@link ApplicationInfo} of the input method. + * @return a display name for this subtype. */ + @NonNull public CharSequence getDisplayName( Context context, String packageName, ApplicationInfo appInfo) { - final Locale locale = getLocaleObject(); - final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale; if (mSubtypeNameResId == 0) { - return localeStr; + return getLocaleDisplayName(getLocaleFromContext(context), getLocaleObject(), + DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU); } + final CharSequence subtypeName = context.getPackageManager().getText( packageName, mSubtypeNameResId, appInfo); - if (!TextUtils.isEmpty(subtypeName)) { - final String replacementString = - containsExtraValueKey(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME) - ? getExtraValueOf(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME) - : localeStr; - try { - return String.format( - subtypeName.toString(), replacementString != null ? replacementString : ""); - } catch (IllegalFormatException e) { - Slog.w(TAG, "Found illegal format in subtype name("+ subtypeName + "): " + e); - return ""; - } + if (TextUtils.isEmpty(subtypeName)) { + return ""; + } + final String subtypeNameString = subtypeName.toString(); + String replacementString; + if (containsExtraValueKey(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) { + replacementString = getExtraValueOf( + EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME); } else { - return localeStr; + final DisplayContext displayContext; + if (TextUtils.equals(subtypeNameString, "%s")) { + displayContext = DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU; + } else if (subtypeNameString.startsWith("%s")) { + displayContext = DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE; + } else { + displayContext = DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE; + } + replacementString = getLocaleDisplayName(getLocaleFromContext(context), + getLocaleObject(), displayContext); + } + if (replacementString == null) { + replacementString = ""; + } + try { + return String.format(subtypeNameString, replacementString); + } catch (IllegalFormatException e) { + Slog.w(TAG, "Found illegal format in subtype name("+ subtypeName + "): " + e); + return ""; + } + } + + @Nullable + private static Locale getLocaleFromContext(@Nullable final Context context) { + if (context == null) { + return null; + } + if (context.getResources() == null) { + return null; + } + final Configuration configuration = context.getResources().getConfiguration(); + if (configuration == null) { + return null; + } + return configuration.getLocales().get(0); + } + + /** + * @param displayLocale {@link Locale} to be used to display {@code localeToDisplay} + * @param localeToDisplay {@link Locale} to be displayed in {@code displayLocale} + * @param displayContext context parameter to be used to display {@code localeToDisplay} in + * {@code displayLocale} + * @return Returns the name of the {@code localeToDisplay} in the user's current locale. + */ + @NonNull + private static String getLocaleDisplayName( + @Nullable Locale displayLocale, @Nullable Locale localeToDisplay, + final DisplayContext displayContext) { + if (localeToDisplay == null) { + return ""; } + final Locale nonNullDisplayLocale = + displayLocale != null ? displayLocale : Locale.getDefault(); + return LocaleDisplayNames + .getInstance(nonNullDisplayLocale, displayContext) + .localeDisplayName(localeToDisplay); } private HashMap<String, String> getExtraValueHashMap() { diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 72202567d9bd..24d2c8ee8fe6 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -58,8 +58,8 @@ public class RadialTimePickerView extends View { private static final String TAG = "RadialTimePickerView"; - private static final int HOURS = 0; - private static final int MINUTES = 1; + public static final int HOURS = 0; + public static final int MINUTES = 1; private static final int HOURS_INNER = 2; private static final int SELECTOR_CIRCLE = 0; diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 6d2cea6b5c3c..a9b7f4e97e7c 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1856,6 +1856,7 @@ public class RemoteViews implements Parcelable, Filter { public static final int LAYOUT_MARGIN_END = 1; /** Set width */ public static final int LAYOUT_WIDTH = 2; + public static final int LAYOUT_MARGIN_BOTTOM = 3; /** * @param viewId ID of the view alter @@ -1898,6 +1899,12 @@ public class RemoteViews implements Parcelable, Filter { target.setLayoutParams(layoutParams); } break; + case LAYOUT_MARGIN_BOTTOM: + if (layoutParams instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = value; + target.setLayoutParams(layoutParams); + } + break; case LAYOUT_WIDTH: layoutParams.width = value; target.setLayoutParams(layoutParams); @@ -2870,6 +2877,16 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}. + * + * @hide + */ + public void setViewLayoutMarginBottom(int viewId, int bottomMargin) { + addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM, + bottomMargin)); + } + + /** * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}. * @hide */ diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index ff10287f3f89..a585d75e5d7a 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -555,7 +555,15 @@ public class TextClock extends TextView { filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - getContext().registerReceiver(mIntentReceiver, filter, null, getHandler()); + // OK, this is gross but needed. This class is supported by the + // remote views mechanism and as a part of that the remote views + // can be inflated by a context for another user without the app + // having interact users permission - just for loading resources. + // For example, when adding widgets from a managed profile to the + // home screen. Therefore, we register the receiver as the user + // the app is running as not the one the context is for. + getContext().registerReceiverAsUser(mIntentReceiver, android.os.Process.myUserHandle(), + filter, null, getHandler()); } private void registerObserver() { diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 4a24e26a2828..0c3892d36aad 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -58,8 +58,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl private static final long DELAY_COMMIT_MILLIS = 2000; // Index used by RadialPickerLayout - private static final int HOUR_INDEX = 0; - private static final int MINUTE_INDEX = 1; + private static final int HOUR_INDEX = RadialTimePickerView.HOURS; + private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES; // NOT a real index for the purpose of what's showing. private static final int AMPM_INDEX = 2; @@ -82,6 +82,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl private final Calendar mTempCalendar; + // Accessibility strings. + private final String mSelectHours; + private final String mSelectMinutes; + private boolean mIsEnabled = true; private boolean mAllowAutoAdvance; private int mInitialHourOfDay; @@ -89,10 +93,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl private boolean mIs24Hour; private boolean mIsAmPmAtStart; - // Accessibility strings. - private String mSelectHours; - private String mSelectMinutes; - // Localization data. private boolean mHourFormatShowLeadingZero; private boolean mHourFormatStartsAtZero; @@ -520,11 +520,15 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl } else { flags |= DateUtils.FORMAT_12HOUR; } + mTempCalendar.set(Calendar.HOUR_OF_DAY, getHour()); mTempCalendar.set(Calendar.MINUTE, getMinute()); - String selectedDate = DateUtils.formatDateTime(mContext, + + final String selectedTime = DateUtils.formatDateTime(mContext, mTempCalendar.getTimeInMillis(), flags); - event.getText().add(selectedDate); + final String selectionMode = mRadialTimePickerView.getCurrentItemShowing() == HOUR_INDEX ? + mSelectHours : mSelectMinutes; + event.getText().add(selectedTime + " " + selectionMode); } /** diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index f2bf9e1d9695..3fc02a7ce5e0 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -16,7 +16,9 @@ package com.android.internal.app; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringRes; import android.app.Activity; import android.app.ActivityThread; import android.app.VoiceInteractor.PickOptionRequest; @@ -24,6 +26,7 @@ import android.app.VoiceInteractor.PickOptionRequest.Option; import android.app.VoiceInteractor.Prompt; import android.content.pm.ComponentInfo; import android.os.AsyncTask; +import android.provider.MediaStore; import android.provider.Settings; import android.text.TextUtils; import android.util.Slog; @@ -119,37 +122,62 @@ public class ResolverActivity extends Activity { } }; + /** + * Get the string resource to be used as a label for the link to the resolver activity for an + * action. + * + * @param action The action to resolve + * + * @return The string resource to be used as a label + */ + public static @StringRes int getLabelRes(String action) { + return ActionTitle.forAction(action).labelRes; + } + private enum ActionTitle { VIEW(Intent.ACTION_VIEW, com.android.internal.R.string.whichViewApplication, - com.android.internal.R.string.whichViewApplicationNamed), + com.android.internal.R.string.whichViewApplicationNamed, + com.android.internal.R.string.whichViewApplicationLabel), EDIT(Intent.ACTION_EDIT, com.android.internal.R.string.whichEditApplication, - com.android.internal.R.string.whichEditApplicationNamed), + com.android.internal.R.string.whichEditApplicationNamed, + com.android.internal.R.string.whichEditApplicationLabel), SEND(Intent.ACTION_SEND, com.android.internal.R.string.whichSendApplication, - com.android.internal.R.string.whichSendApplicationNamed), + com.android.internal.R.string.whichSendApplicationNamed, + com.android.internal.R.string.whichSendApplicationLabel), SENDTO(Intent.ACTION_SENDTO, com.android.internal.R.string.whichSendToApplication, - com.android.internal.R.string.whichSendToApplicationNamed), + com.android.internal.R.string.whichSendToApplicationNamed, + com.android.internal.R.string.whichSendToApplicationLabel), SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE, com.android.internal.R.string.whichSendApplication, - com.android.internal.R.string.whichSendApplicationNamed), + com.android.internal.R.string.whichSendApplicationNamed, + com.android.internal.R.string.whichSendApplicationLabel), + CAPTURE_IMAGE(MediaStore.ACTION_IMAGE_CAPTURE, + com.android.internal.R.string.whichImageCaptureApplication, + com.android.internal.R.string.whichImageCaptureApplicationNamed, + com.android.internal.R.string.whichImageCaptureApplicationLabel), DEFAULT(null, com.android.internal.R.string.whichApplication, - com.android.internal.R.string.whichApplicationNamed), + com.android.internal.R.string.whichApplicationNamed, + com.android.internal.R.string.whichApplicationLabel), HOME(Intent.ACTION_MAIN, com.android.internal.R.string.whichHomeApplication, - com.android.internal.R.string.whichHomeApplicationNamed); + com.android.internal.R.string.whichHomeApplicationNamed, + com.android.internal.R.string.whichHomeApplicationLabel); public final String action; public final int titleRes; public final int namedTitleRes; + public final @StringRes int labelRes; - ActionTitle(String action, int titleRes, int namedTitleRes) { + ActionTitle(String action, int titleRes, int namedTitleRes, @StringRes int labelRes) { this.action = action; this.titleRes = titleRes; this.namedTitleRes = namedTitleRes; + this.labelRes = labelRes; } public static ActionTitle forAction(String action) { @@ -760,7 +788,7 @@ public class ResolverActivity extends Activity { } else { try { AppGlobals.getPackageManager().setLastChosenActivity(intent, - intent.resolveTypeIfNeeded(getContentResolver()), + intent.resolveType(getContentResolver()), PackageManager.MATCH_DEFAULT_ONLY, filter, bestMatch, intent.getComponent()); } catch (RemoteException re) { diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index 06542f7af7e7..2f80b862c72b 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -516,7 +516,7 @@ public final class ProcessStats implements Parcelable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); - int bottom = (int)(val&0xfffffff); + int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java index 76102af9bcb0..f941836d2c09 100644 --- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java +++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java @@ -68,11 +68,8 @@ public class SparseMappingTable { * A table of data as stored in a SparseMappingTable. */ public static class Table { - // When mSequence is this this our data better be empty - private static final int UNINITIALIZED_SEQUENCE = -1; - private SparseMappingTable mParent; - private int mSequence = UNINITIALIZED_SEQUENCE; + private int mSequence = 1; private int[] mTable; private int mSize; @@ -119,12 +116,6 @@ public class SparseMappingTable { * but should be considered opaque to the caller. */ public int getOrAddKey(byte id, int count) { - // This is the only place we add data to mParent.mLongs, so this is the time - // to update our sequence to match there. - if (mSequence == UNINITIALIZED_SEQUENCE) { - mSequence = mParent.mSequence; - } - assertConsistency(); final int idx = binarySearch(id); @@ -311,7 +302,7 @@ public class SparseMappingTable { // Reset our sequence number. This will make all read/write calls // start to fail, and then when we re-allocate it will be re-synced // to that of mParent. - mSequence = UNINITIALIZED_SEQUENCE; + mSequence = mParent.mSequence; } /** @@ -377,27 +368,19 @@ public class SparseMappingTable { // Original bug: b/27045736 // New bug: b/27960286 if (false) { - // Assert that our sequence number has been initialized. If it hasn't - // that means someone tried to read or write data without allocating it - // since we were created or reset. - if (mSequence == UNINITIALIZED_SEQUENCE) { - logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in" - + " SparseMappingTable.Table. -- " - + dumpInternalState()); - return; - } - // Assert that our sequence number matches mParent's. If it isn't that means - // we have been reset and our + // we have been reset and our. If our sequence is UNITIALIZED_SEQUENCE, then + // it's possible that everything is working fine and we just haven't been + // written to since the last resetTable(). if (mSequence != mParent.mSequence) { if (mSequence < mParent.mSequence) { - logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()" + logOrThrow("Sequence mismatch. SparseMappingTable.reset()" + " called but not Table.resetTable() -- " + dumpInternalState()); return; } else if (mSequence > mParent.mSequence) { logOrThrow("Sequence mismatch. Table.resetTable()" - + " called but not SparseMappingTable.resetTable() -- " + + " called but not SparseMappingTable.reset() -- " + dumpInternalState()); return; } @@ -494,6 +477,10 @@ public class SparseMappingTable { } } + public SparseMappingTable() { + mLongs.add(new long[ARRAY_SIZE]); + } + /** * Wipe out all the data. */ @@ -545,6 +532,35 @@ public class SparseMappingTable { } /** + * Return a string for debugging. + */ + public String dumpInternalState(boolean includeData) { + final StringBuilder sb = new StringBuilder(); + sb.append("SparseMappingTable{"); + sb.append("mSequence="); + sb.append(mSequence); + sb.append(" mNextIndex="); + sb.append(mNextIndex); + sb.append(" mLongs.size="); + final int N = mLongs.size(); + sb.append(N); + sb.append("\n"); + if (includeData) { + for (int i=0; i<N; i++) { + final long[] array = mLongs.get(i); + for (int j=0; j<array.length; j++) { + if (i == N-1 && j == mNextIndex) { + break; + } + sb.append(String.format(" %4d %d 0x%016x %-19d\n", i, j, array[j], array[j])); + } + } + } + sb.append("}"); + return sb.toString(); + } + + /** * Write the long array to the parcel in a compacted form. Does not allow negative * values in the array. */ @@ -559,7 +575,7 @@ public class SparseMappingTable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); - int bottom = (int)(val&0xfffffff); + int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 5980ab69d7a4..78b5d61d3f1a 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -43,6 +43,7 @@ import com.android.internal.os.InstallerConnection.InstallerException; import dalvik.system.DexFile; import dalvik.system.PathClassLoader; import dalvik.system.VMRuntime; +import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; @@ -597,6 +598,10 @@ public class ZygoteInit { } public static void main(String argv[]) { + // Mark zygote start. This ensures that thread creation will throw + // an error. + ZygoteHooks.startZygoteNoThreadCreation(); + try { Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit"); RuntimeInit.enableDdms(); @@ -648,6 +653,8 @@ public class ZygoteInit { // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); + ZygoteHooks.stopZygoteNoThreadCreation(); + if (startSystemServer) { startSystemServer(abiList, socketName); } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index f9ac5632b49b..3aa771971cf2 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -210,7 +210,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private Drawable mResizingBackgroundDrawable; private Drawable mCaptionBackgroundDrawable; private Drawable mUserCaptionBackgroundDrawable; - private Drawable mOriginalBackgroundDrawable; private float mAvailableWidth; @@ -891,11 +890,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mBackgroundPadding.setEmpty(); } drawableChanged(); - - // Make sure we don't reset to the old drawable when finishing resizing. - if (mResizeMode != RESIZE_MODE_INVALID) { - mOriginalBackgroundDrawable = null; - } } } @@ -1960,9 +1954,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateElevation(); updateColorViews(null /* insets */, false); - - mOriginalBackgroundDrawable = getBackground(); - setBackgroundDrawable(null); } mResizeMode = resizeMode; getViewRootImpl().requestInvalidateRootRenderNode(); @@ -1974,10 +1965,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateColorViews(null /* insets */, false); mResizeMode = RESIZE_MODE_INVALID; getViewRootImpl().requestInvalidateRootRenderNode(); - if (mOriginalBackgroundDrawable != null) { - setBackgroundDrawable(mOriginalBackgroundDrawable); - mOriginalBackgroundDrawable = null; - } } @Override diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java index 78c5e34ba108..e2d8ffc4d9b1 100644 --- a/core/java/com/android/internal/widget/ImageFloatingTextView.java +++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java @@ -16,13 +16,18 @@ package com.android.internal.widget; +import com.android.internal.R; + import android.annotation.Nullable; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; import android.text.BoringLayout; import android.text.Layout; import android.text.StaticLayout; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.RemotableViewMethod; import android.widget.RemoteViews; import android.widget.TextView; @@ -35,7 +40,8 @@ import android.widget.TextView; @RemoteViews.RemoteView public class ImageFloatingTextView extends TextView { - private boolean mHasImage; + /** Number of lines from the top to indent */ + private int mIndentLines; public ImageFloatingTextView(Context context) { this(context, null); @@ -69,10 +75,16 @@ public class ImageFloatingTextView extends TextView { .setEllipsizedWidth(ellipsisWidth) .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - // we set the endmargin on the first 2 lines. this works just in our case but that's - // sufficient for now. - int endMargin = (int) (getResources().getDisplayMetrics().density * 52); - int[] margins = mHasImage ? new int[] {endMargin, endMargin, 0} : null; + // we set the endmargin on the requested number of lines. + int endMargin = getContext().getResources().getDimensionPixelSize( + R.dimen.notification_content_picture_margin); + int[] margins = null; + if (mIndentLines > 0) { + margins = new int[mIndentLines + 1]; + for (int i = 0; i < mIndentLines; i++) { + margins[i] = endMargin; + } + } if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { builder.setIndents(margins, null); } else { @@ -84,8 +96,22 @@ public class ImageFloatingTextView extends TextView { @RemotableViewMethod public void setHasImage(boolean hasImage) { - mHasImage = hasImage; + mIndentLines = hasImage ? 2 : 0; // The new layout will be automatically created when the text is // set again by the notification. } + + /** + * @param lines the number of lines at the top that should be indented by indentEnd + * @return whether a change was made + */ + public boolean setNumIndentLines(int lines) { + if (mIndentLines != lines) { + mIndentLines = lines; + // Invalidate layout. + setHint(getHint()); + return true; + } + return false; + } } diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java new file mode 100644 index 000000000000..dc7b7f5b9646 --- /dev/null +++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java @@ -0,0 +1,278 @@ +/* + * 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 + */ + +package com.android.internal.widget; + +import com.android.internal.R; + +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.RemotableViewMethod; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RemoteViews; + +/** + * A custom-built layout for the Notification.MessagingStyle. + * + * Evicts children until they all fit. + */ +@RemoteViews.RemoteView +public class MessagingLinearLayout extends ViewGroup { + + /** + * Spacing to be applied between views. + */ + private int mSpacing; + + /** + * The maximum height allowed. + */ + private int mMaxHeight; + + private int mIndentLines; + + public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.MessagingLinearLayout, 0, + 0); + + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + int attr = a.getIndex(i); + switch (attr) { + case R.styleable.MessagingLinearLayout_maxHeight: + mMaxHeight = a.getDimensionPixelSize(i, 0); + break; + case R.styleable.MessagingLinearLayout_spacing: + mSpacing = a.getDimensionPixelSize(i, 0); + break; + } + } + + if (mMaxHeight <= 0) { + throw new IllegalStateException( + "MessagingLinearLayout: Must specify positive maxHeight"); + } + + a.recycle(); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // This is essentially a bottom-up linear layout that only adds children that fit entirely + // up to a maximum height. + + switch (MeasureSpec.getMode(heightMeasureSpec)) { + case MeasureSpec.AT_MOST: + heightMeasureSpec = MeasureSpec.makeMeasureSpec( + Math.min(mMaxHeight, MeasureSpec.getSize(heightMeasureSpec)), + MeasureSpec.AT_MOST); + break; + case MeasureSpec.UNSPECIFIED: + heightMeasureSpec = MeasureSpec.makeMeasureSpec( + mMaxHeight, + MeasureSpec.AT_MOST); + break; + case MeasureSpec.EXACTLY: + break; + } + final int targetHeight = MeasureSpec.getSize(heightMeasureSpec); + final int count = getChildCount(); + + for (int i = 0; i < count; ++i) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.hide = true; + } + + int totalHeight = mPaddingTop + mPaddingBottom; + boolean first = true; + + // Starting from the bottom: we measure every view as if it were the only one. If it still + // fits, we take it, otherwise we stop there. + for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) { + if (getChildAt(i).getVisibility() == GONE) { + continue; + } + final View child = getChildAt(i); + LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); + + if (child instanceof ImageFloatingTextView) { + // Pretend we need the image padding for all views, we don't know which + // one will end up needing to do this (might end up not using all the space, + // but calculating this exactly would be more expensive). + ((ImageFloatingTextView) child).setNumIndentLines(mIndentLines); + } + + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + + final int childHeight = child.getMeasuredHeight(); + int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin + + lp.bottomMargin + (first ? 0 : mSpacing)); + first = false; + + if (newHeight <= targetHeight) { + totalHeight = newHeight; + lp.hide = false; + } else { + break; + } + } + + // Now that we know which views to take, fix up the indents and see what width we get. + int measuredWidth = mPaddingLeft + mPaddingRight; + int imageLines = mIndentLines; + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (child.getVisibility() == GONE || lp.hide) { + continue; + } + + if (child instanceof ImageFloatingTextView) { + ImageFloatingTextView textChild = (ImageFloatingTextView) child; + if (imageLines == 2 && textChild.getLineCount() > 2) { + // HACK: If we need indent for two lines, and they're coming from the same + // view, we need extra spacing to compensate for the lack of margins, + // so add an extra line of indent. + imageLines = 3; + } + boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines)); + if (changed) { + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + } + imageLines -= textChild.getLineCount(); + } + + measuredWidth = Math.max(measuredWidth, + child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + + mPaddingLeft + mPaddingRight); + } + + + setMeasuredDimension( + resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), + widthMeasureSpec), + resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight), + heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int paddingLeft = mPaddingLeft; + + int childTop; + + // Where right end of child should go + final int width = right - left; + final int childRight = width - mPaddingRight; + + final int layoutDirection = getLayoutDirection(); + final int count = getChildCount(); + + childTop = mPaddingTop; + + boolean first = true; + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (child.getVisibility() == GONE || lp.hide) { + continue; + } + + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + + int childLeft; + if (layoutDirection == LAYOUT_DIRECTION_RTL) { + childLeft = childRight - childWidth - lp.rightMargin; + } else { + childLeft = paddingLeft + lp.leftMargin; + } + + if (!first) { + childTop += mSpacing; + } + + childTop += lp.topMargin; + child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); + + childTop += childHeight + lp.bottomMargin; + + first = false; + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp.hide) { + return true; + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(mContext, attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + LayoutParams copy = new LayoutParams(lp.width, lp.height); + if (lp instanceof MarginLayoutParams) { + copy.copyMarginsFrom((MarginLayoutParams) lp); + } + return copy; + } + + @RemotableViewMethod + /** + * Sets how many lines should be indented to avoid a floating image. + */ + public void setNumIndentLines(int numberLines) { + mIndentLines = numberLines; + } + + public static class LayoutParams extends MarginLayoutParams { + + boolean hide = false; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + } +} diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp index e5c4a2d0cfcf..50d86fffe29d 100644 --- a/core/jni/android_graphics_drawable_VectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp @@ -343,7 +343,7 @@ static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPa } static const JNINativeMethod gMethods[] = { - {"nCreateRenderer", "!(J)J", (void*)createTree}, + {"nCreateTree", "!(J)J", (void*)createTree}, {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize}, {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha}, {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha}, diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index 90d69d256ec7..5c961d96cf56 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -370,10 +370,6 @@ int handle_os_message(uint32_t msgType, uint32_t hubHandle, retVal = 0; break; - case CONTEXT_HUB_LOAD_OS: - retVal = 0; - break; - default: retVal = -1; break; diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 3d6520903a7b..faa41921ba11 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -663,6 +663,14 @@ static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env, proxy->setContentDrawBounds(left, top, right, bottom); } +static jboolean android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env, + jobject clazz, jobject jsurface, jobject jbitmap) { + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); + sp<Surface> surface = android_view_Surface_getSurface(env, jsurface); + return RenderProxy::copySurfaceInto(surface, &bitmap); +} + // ---------------------------------------------------------------------------- // FrameMetricsObserver // ---------------------------------------------------------------------------- @@ -768,6 +776,8 @@ static const JNINativeMethod gMethods[] = { { "nRemoveFrameMetricsObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver }, + { "nCopySurfaceInto", "(Landroid/view/Surface;Landroid/graphics/Bitmap;)Z", + (void*)android_view_ThreadedRenderer_copySurfaceInto }, }; int register_android_view_ThreadedRenderer(JNIEnv* env) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9a2e39c752de..778f79761441 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -420,6 +420,7 @@ <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" /> <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" /> <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" /> + <protected-broadcast android:name="com.android.server.action.RESET_TWILIGHT_AUTO" /> <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" /> <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" /> <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" /> diff --git a/core/res/res/drawable-hdpi/ic_launcher_android.png b/core/res/res/drawable-hdpi/ic_launcher_android.png Binary files differindex cce518787b58..2e9b196c9625 100644 --- a/core/res/res/drawable-hdpi/ic_launcher_android.png +++ b/core/res/res/drawable-hdpi/ic_launcher_android.png diff --git a/core/res/res/drawable-ldpi/ic_launcher_android.png b/core/res/res/drawable-ldpi/ic_launcher_android.png Binary files differindex 628a8de9a0bb..245e4b771f17 100644 --- a/core/res/res/drawable-ldpi/ic_launcher_android.png +++ b/core/res/res/drawable-ldpi/ic_launcher_android.png diff --git a/core/res/res/drawable-mdpi/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png Binary files differindex 6a97d5b79a28..baacd4f23e43 100644 --- a/core/res/res/drawable-mdpi/ic_launcher_android.png +++ b/core/res/res/drawable-mdpi/ic_launcher_android.png diff --git a/core/res/res/drawable-xhdpi/ic_launcher_android.png b/core/res/res/drawable-xhdpi/ic_launcher_android.png Binary files differindex b1097d6a6279..00b69a53a62b 100644 --- a/core/res/res/drawable-xhdpi/ic_launcher_android.png +++ b/core/res/res/drawable-xhdpi/ic_launcher_android.png diff --git a/core/res/res/drawable-xxhdpi/ic_launcher_android.png b/core/res/res/drawable-xxhdpi/ic_launcher_android.png Binary files differnew file mode 100644 index 000000000000..ad05cd5b337b --- /dev/null +++ b/core/res/res/drawable-xxhdpi/ic_launcher_android.png diff --git a/core/res/res/drawable/ic_input_extract_action_done.xml b/core/res/res/drawable/ic_input_extract_action_done.xml new file mode 100644 index 000000000000..f6e872eeb694 --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_done.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M18,32.34L9.66,24l-2.83,2.83L18,38l24,-24 -2.83,-2.83z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_go.xml b/core/res/res/drawable/ic_input_extract_action_go.xml new file mode 100644 index 000000000000..edbc826b1cb2 --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_go.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M6,22h28.34l-7.17,-7.17L30,12l12,12 -12,12 -2.83,-2.83L34.34,26H6z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_next.xml b/core/res/res/drawable/ic_input_extract_action_next.xml new file mode 100644 index 000000000000..ffef3466f52b --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_next.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M23.17,14.83L30.34,22H2v4h28.34l-7.17,7.17L26,36l12,-12 -12,-12 -2.83,2.83zM40,12v24h4V12h-4z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_previous.xml b/core/res/res/drawable/ic_input_extract_action_previous.xml new file mode 100644 index 000000000000..89777b0471b0 --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_previous.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M22.83,14.83L15.66,22H44v4H15.66l7.17,7.17L20,36 8,24l12,-12 2.83,2.83zM6,12v24H2V12h4z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_return.xml b/core/res/res/drawable/ic_input_extract_action_return.xml new file mode 100644 index 000000000000..cb2de5ad8185 --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_return.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M38,14v8H11.66l7.17,-7.17L16,12 4,24l12,12 2.83,-2.83L11.66,26H42V14z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_search.xml b/core/res/res/drawable/ic_input_extract_action_search.xml new file mode 100644 index 000000000000..dcbcdbfcba62 --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_search.xml @@ -0,0 +1,19 @@ +<!-- + 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 android:height="24dp" android:viewportHeight="48.0" + android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FFFFFF" android:pathData="M31,28h-1.59l-0.55,-0.55C30.82,25.18 32,22.23 32,19c0,-7.18 -5.82,-13 -13,-13S6,11.82 6,19s5.82,13 13,13c3.23,0 6.18,-1.18 8.45,-3.13l0.55,0.55L28,31l10,9.98L40.98,38 31,28zM19,28c-4.97,0 -9,-4.03 -9,-9s4.03,-9 9,-9 9,4.03 9,9 -4.03,9 -9,9z"/> +</vector> diff --git a/core/res/res/drawable/ic_input_extract_action_send.xml b/core/res/res/drawable/ic_input_extract_action_send.xml new file mode 100644 index 000000000000..6494bee5f4cd --- /dev/null +++ b/core/res/res/drawable/ic_input_extract_action_send.xml @@ -0,0 +1,24 @@ +<!-- + 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="36dp" + android:height="36dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:pathData="M4.02,42L46,24 4.02,6 4,20l30,4 -30,4z" + android:fillColor="#FFFFFF"/> +</vector> diff --git a/core/res/res/drawable/input_extract_action_bg_material_dark.xml b/core/res/res/drawable/input_extract_action_bg_material_dark.xml new file mode 100644 index 000000000000..9c6a6c3d190a --- /dev/null +++ b/core/res/res/drawable/input_extract_action_bg_material_dark.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/input_extract_action_bg_pressed_material_dark" + android:state_pressed="true"/> + <item android:drawable="@drawable/input_extract_action_bg_normal_material_dark"/> +</selector> diff --git a/core/res/res/drawable/input_extract_action_bg_normal_material_dark.xml b/core/res/res/drawable/input_extract_action_bg_normal_material_dark.xml new file mode 100644 index 000000000000..8449978b590a --- /dev/null +++ b/core/res/res/drawable/input_extract_action_bg_normal_material_dark.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> + <solid android:color="@color/material_deep_teal_200"/> +</shape> diff --git a/core/res/res/drawable/input_extract_action_bg_pressed_material_dark.xml b/core/res/res/drawable/input_extract_action_bg_pressed_material_dark.xml new file mode 100644 index 000000000000..adade10437e2 --- /dev/null +++ b/core/res/res/drawable/input_extract_action_bg_pressed_material_dark.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> + <solid android:color="@color/material_deep_teal_100"/> +</shape> diff --git a/core/res/res/layout-watch/input_method_extract_view.xml b/core/res/res/layout-watch/input_method_extract_view.xml new file mode 100644 index 000000000000..e3cd2ce7c1e8 --- /dev/null +++ b/core/res/res/layout-watch/input_method_extract_view.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<android.inputmethodservice.CompactExtractEditLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical" + android:baselineAligned="false"> + + <android.inputmethodservice.ExtractEditText + android:id="@id/inputExtractEditText" + android:layout_width="0dp" + android:layout_height="24dp" + android:background="@null" + android:singleLine="true" + android:inputType="text" + android:layout_weight="1" + android:fontFamily="sans-serif-condensed-light" + android:textColor="@color/primary_text_default_material_dark" + android:textColorHighlight="@color/accent_material_dark" + android:textSize="18dp" + android:cursorVisible="false" + android:gravity="bottom|right" + /> + + <FrameLayout + android:id="@id/inputExtractAccessories" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:visibility="visible"> + <ImageButton + android:id="@id/inputExtractAction" + android:layout_width="@dimen/input_extract_action_button_width" + android:layout_height="@dimen/input_extract_action_button_width" + android:background="@drawable/input_extract_action_bg_material_dark" + android:padding="4dp" + android:scaleType="centerInside" /> + </FrameLayout> +</android.inputmethodservice.CompactExtractEditLayout> diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml new file mode 100644 index 000000000000..7d718e0db991 --- /dev/null +++ b/core/res/res/layout/notification_template_material_messaging.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:tag="messaging" + > + <include layout="@layout/notification_template_header" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="top" + android:layout_marginTop="@dimen/notification_content_margin_top" + android:clipToPadding="false" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/notification_main_column" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:paddingStart="@dimen/notification_content_margin_start" + android:paddingEnd="@dimen/notification_content_margin_end" + android:minHeight="@dimen/notification_min_content_height" + android:clipToPadding="false" + android:orientation="vertical" + > + <include layout="@layout/notification_template_part_line1" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <com.android.internal.widget.MessagingLinearLayout + android:id="@+id/notification_messaging" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/notification_content_margin_bottom" + android:spacing="@dimen/notification_messaging_spacing" + android:maxHeight="212dp"> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text0" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text1" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text2" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text3" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text4" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text5" + style="@style/Widget.Material.Notification.MessagingText" + /> + <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text6" + style="@style/Widget.Material.Notification.MessagingText" + /> + </com.android.internal.widget.MessagingLinearLayout> + </LinearLayout> + <include layout="@layout/notification_material_action_list" /> + </LinearLayout> + <include layout="@layout/notification_template_right_icon" /> +</FrameLayout> diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml index 15ccc6729792..b652127e85bd 100644 --- a/core/res/res/layout/notification_template_right_icon.xml +++ b/core/res/res/layout/notification_template_right_icon.xml @@ -16,9 +16,9 @@ --> <ImageView android:id="@+id/right_icon" xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_marginEnd="16dp" + android:layout_width="@dimen/notification_large_icon_width" + android:layout_height="@dimen/notification_large_icon_width" + android:layout_marginEnd="@dimen/notification_content_margin_end" android:layout_marginTop="36dp" android:layout_gravity="top|end" android:scaleType="centerCrop" diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml index 4b8640c91f70..5850e5090926 100644 --- a/core/res/res/layout/resolver_list.xml +++ b/core/res/res/layout/resolver_list.xml @@ -72,7 +72,9 @@ <TextView android:id="@+id/empty" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:background="@color/white" + android:elevation="8dp" android:layout_alwaysShow="true" android:text="@string/noApplications" android:padding="32dp" diff --git a/core/res/res/values-round-watch/dimens.xml b/core/res/res/values-round-watch/dimens.xml new file mode 100644 index 000000000000..a12f49929929 --- /dev/null +++ b/core/res/res/values-round-watch/dimens.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- each of these are relative to the display size --> + <item name="input_extract_layout_height" type="fraction">25.2%</item> + <item name="input_extract_layout_padding_left" type="fraction">7.5%</item> + <item name="input_extract_layout_padding_left_no_action" type="fraction">@fraction/input_extract_layout_padding_right</item> + <item name="input_extract_layout_padding_right" type="fraction">21.4%</item> + <item name="input_extract_text_margin_bottom" type="fraction">5.5%</item> + <item name="input_extract_action_margin_bottom" type="fraction">2.1%</item> + <item name="input_extract_action_button_width" type="dimen">32dp</item> + <item name="input_extract_action_button_height" type="dimen">32dp</item> +</resources> diff --git a/core/res/res/values-w170dp-notround-watch/dimens.xml b/core/res/res/values-w170dp-notround-watch/dimens.xml new file mode 100644 index 000000000000..c91cbc197c56 --- /dev/null +++ b/core/res/res/values-w170dp-notround-watch/dimens.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- each of these are relative to the display size --> + <item name="input_extract_layout_padding_right" type="fraction">7.5%</item> +</resources> diff --git a/core/res/res/values-watch/dimens.xml b/core/res/res/values-watch/dimens.xml new file mode 100644 index 000000000000..f103aa91dcfe --- /dev/null +++ b/core/res/res/values-watch/dimens.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- each of these are relative to the display size --> + <item name="input_extract_layout_height" type="fraction">17.5%</item> + <item name="input_extract_layout_padding_left" type="fraction">3.6%</item> + <item name="input_extract_layout_padding_left_no_action" type="fraction">@fraction/input_extract_layout_padding_right</item> + <item name="input_extract_layout_padding_right" type="fraction">2.5%</item> + <item name="input_extract_text_margin_bottom" type="fraction">0%</item> + <item name="input_extract_action_margin_bottom" type="fraction">0%</item> + <item name="input_extract_action_button_width" type="dimen">24dp</item> + <item name="input_extract_action_button_height" type="dimen">24dp</item> +</resources> diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml index 756a94b4185c..6d6065f68ed4 100644 --- a/core/res/res/values-watch/themes.xml +++ b/core/res/res/values-watch/themes.xml @@ -18,6 +18,7 @@ <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" /> <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> + <style name="Theme.InputMethod" parent="Theme.Micro.InputMethod" /> <style name="Theme.Material.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> </resources> diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml index 61753b1f0211..66509fb86eaa 100644 --- a/core/res/res/values-watch/themes_device_defaults.xml +++ b/core/res/res/values-watch/themes_device_defaults.xml @@ -19,14 +19,16 @@ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Micro.Dialog" /> <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Micro.Dialog" /> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> + <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Micro.InputMethod" /> + <style name="Theme.DeviceDefault.Panel" parent="Theme.Micro.Panel" /> <style name="Theme.DeviceDefault.Light" parent="Theme.Micro.Light" /> <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Micro.Light" /> <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Micro.Light" /> <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" /> <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Micro.Dialog" /> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> + <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Micro.Light.Panel" /> <style name="Theme.DeviceDefault.Settings" parent="Theme.Micro" /> <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Micro" /> - </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 0ed1f133c627..a320ef63face 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8129,6 +8129,11 @@ i <attr name="maxCollapsedHeightSmall" format="dimension" /> </declare-styleable> + <declare-styleable name="MessagingLinearLayout"> + <attr name="maxHeight" /> + <attr name="spacing" /> + </declare-styleable> + <declare-styleable name="ResolverDrawerLayout_LayoutParams"> <attr name="layout_alwaysShow" format="boolean" /> <attr name="layout_ignoreOffset" format="boolean" /> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index 7399fa9d58ce..c8ca11689299 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -75,7 +75,9 @@ <color name="material_grey_100">#fff5f5f5</color> <color name="material_grey_50">#fffafafa</color> + <color name="material_deep_teal_100">#ffb2dfdb</color> <color name="material_deep_teal_200">#ff80cbc4</color> + <color name="material_deep_teal_300">#ff4db6ac</color> <color name="material_deep_teal_500">#ff009688</color> <color name="material_blue_grey_800">#ff37474f</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index cb551e8df695..aada05d4bf82 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -520,12 +520,6 @@ <!-- Wifi driver supports batched scan --> <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool> - <!-- Wifi HAL supported PNO --> - <bool translatable="false" name="config_wifi_hal_pno_enable">false</bool> - - <!-- Wifi SSID white list (can't be enabled if config_wifi_hal_pno_enable is not) --> - <bool translatable="false" name="config_wifi_ssid_white_list_enable">true</bool> - <!-- Idle Receive current for wifi radio. 0 by default--> <integer translatable="false" name="config_wifi_idle_receive_cur_ma">0</integer> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index dd54d57058af..9178305159b9 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -162,9 +162,9 @@ <dimen name="notification_min_height">92dp</dimen> <!-- The width of the big icons in notifications. --> - <dimen name="notification_large_icon_width">64dp</dimen> + <dimen name="notification_large_icon_width">40dp</dimen> <!-- The width of the big icons in notifications. --> - <dimen name="notification_large_icon_height">64dp</dimen> + <dimen name="notification_large_icon_height">40dp</dimen> <!-- The minimum width of the app name in the header if it shrinks --> <dimen name="notification_header_shrink_min_width">72dp</dimen> @@ -181,6 +181,9 @@ <!-- The margin of the content to an image--> <dimen name="notification_content_image_margin_end">8dp</dimen> + <!-- The spacing between messages in Notification.MessagingStyle --> + <dimen name="notification_messaging_spacing">6dp</dimen> + <!-- Preferred width of the search view. --> <dimen name="search_view_preferred_width">320dip</dimen> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 96731cf33ece..fa799c985f52 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -349,18 +349,18 @@ <!-- SSL CA cert notification --> <skip /> <!-- Shows up when there is a user SSL CA Cert installed on the device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] --> - <string name="ssl_ca_cert_warning">Network may be monitored</string> - <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning", - i.e. "Network may be monitored". This says that an unknown party is doing the monitoring. - [CHAR LIMIT=100]--> + <plurals name="ssl_ca_cert_warning"> + <item quantity="one">Certificate authority installed</item> + <item quantity="other">Certificate authorities installed</item> + </plurals> + <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning". + This says that an unknown party is doing the monitoring. [CHAR LIMIT=100]--> <string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string> - <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning", - i.e. "Network may be monitored". This indicates that an unspecified administrator is doing - the monitoring. [CHAR LIMIT=100]--> + <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning". + This indicates that an unspecified administrator is doing the monitoring. [CHAR LIMIT=100]--> <string name="ssl_ca_cert_noti_by_administrator">By your work profile administrator</string> - <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning", - i.e. "Network may be monitored". This indicates who is doing the monitoring. - [CHAR LIMIT=100]--> + <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning". + This indicates who is doing the monitoring. [CHAR LIMIT=100]--> <string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string> <!-- Work profile deleted notification--> <skip /> @@ -2552,21 +2552,29 @@ <!-- Title of intent resolver dialog when selecting an application to run and a previously used application is known. --> <string name="whichApplicationNamed">Complete action using %1$s</string> + <!-- Generic label for a link to a intent resolver. --> + <string name="whichApplicationLabel">Complete action</string> <!-- Title of intent resolver dialog when selecting a viewer application to run. --> <string name="whichViewApplication">Open with</string> <!-- Title of intent resolver dialog when selecting a viewer application to run and a previously used application is known. --> <string name="whichViewApplicationNamed">Open with %1$s</string> + <!-- Label for a link to a intent resolver dialog to view something --> + <string name="whichViewApplicationLabel">Open</string> <!-- Title of intent resolver dialog when selecting an editor application to run. --> <string name="whichEditApplication">Edit with</string> <!-- Title of intent resolver dialog when selecting an editor application to run and a previously used application is known. --> <string name="whichEditApplicationNamed">Edit with %1$s</string> + <!-- Label for a link to a intent resolver dialog when selecting an editor application --> + <string name="whichEditApplicationLabel">Edit</string> <!-- Title of intent resolver dialog when selecting a sharing application to run. --> <string name="whichSendApplication">Share with</string> <!-- Title of intent resolver dialog when selecting a sharing application to run and a previously used application is known. --> <string name="whichSendApplicationNamed">Share with %1$s</string> + <!-- Label for a link to a intent resolver dialog to sharing something --> + <string name="whichSendApplicationLabel">Share</string> <!-- Title of intent resolver dialog when selecting an application to run to send content to a specific recipient. Often used for email. --> <string name="whichSendToApplication">Send using</string> @@ -2574,11 +2582,23 @@ send content to a specific recipient and a previously used application is known. Often used for email. --> <string name="whichSendToApplicationNamed">Send using %1$s</string> + <!-- Label for a link to a intent resolver dialog to send content to a specific recipient. --> + <string name="whichSendToApplicationLabel">Send</string> <!-- Title of intent resolver dialog when selecting a HOME application to run. --> <string name="whichHomeApplication">Select a Home app</string> <!-- Title of intent resolver dialog when selecting a HOME application to run and a previously used application is known. --> <string name="whichHomeApplicationNamed">Use %1$s as Home</string> + <!-- Label for a link to a intent resolver dialog when selecting a HOME --> + <string name="whichHomeApplicationLabel">Capture image</string> + <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title--> + <!-- Title of intent resolver dialog when capturing an image. --> + <string name="whichImageCaptureApplication">Capture image with</string> + <!-- Title of intent resolver dialog when capturing an image + and a previously used application is known. --> + <string name="whichImageCaptureApplicationNamed">Capture image with %1$s</string> + <!-- Label for a link to a intent resolver dialog when capturing an image --> + <string name="whichImageCaptureApplicationLabel">Capture image</string> <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title--> <string name="alwaysUse">Use by default for this action.</string> <!-- Title of the list of alternate options to complete an action shown when the diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 2420c1a96a6c..8a33406eeaa7 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -456,6 +456,14 @@ please see styles_device_defaults.xml. <style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" /> + <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Light.TextView"> + <item name="layout_width">match_parent</item> + <item name="layout_height">wrap_content</item> + <item name="ellipsize">end</item> + <item name="visibility">gone</item> + <item name="textAppearance">@style/TextAppearance.Material.Notification</item> + </style> + <!-- Widget Styles --> <style name="Material"/> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 29c6951557ec..e37f8d567c93 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -390,9 +390,7 @@ <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" /> <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" /> <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" /> - <java-symbol type="bool" name="config_wifi_hal_pno_enable" /> <java-symbol type="integer" name="config_windowOutsetBottom" /> - <java-symbol type="bool" name="config_wifi_ssid_white_list_enable" /> <java-symbol type="integer" name="db_connection_pool_size" /> <java-symbol type="integer" name="db_journal_size_limit" /> <java-symbol type="integer" name="db_wal_autocheckpoint" /> @@ -1097,7 +1095,6 @@ <java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" /> <java-symbol type="string" name="ssl_ca_cert_noti_by_administrator" /> <java-symbol type="string" name="ssl_ca_cert_noti_managed" /> - <java-symbol type="string" name="ssl_ca_cert_warning" /> <java-symbol type="string" name="work_profile_deleted" /> <java-symbol type="string" name="work_profile_deleted_description" /> <java-symbol type="string" name="work_profile_deleted_details" /> @@ -1117,6 +1114,7 @@ <java-symbol type="plurals" name="matches_found" /> <java-symbol type="plurals" name="restr_pin_countdown" /> <java-symbol type="plurals" name="pinpuk_attempts" /> + <java-symbol type="plurals" name="ssl_ca_cert_warning" /> <java-symbol type="array" name="carrier_properties" /> <java-symbol type="array" name="config_sms_enabled_locking_shift_tables" /> @@ -1388,7 +1386,6 @@ <java-symbol type="xml" name="password_kbd_qwerty" /> <java-symbol type="xml" name="autotext" /> - <java-symbol type="xml" name="eri" /> <java-symbol type="xml" name="password_kbd_numeric" /> <java-symbol type="xml" name="password_kbd_qwerty_shifted" /> <java-symbol type="xml" name="password_kbd_symbols" /> @@ -2201,14 +2198,22 @@ <java-symbol type="attr" name="touchscreenBlocksFocus" /> <java-symbol type="layout" name="resolver_list_with_default" /> <java-symbol type="string" name="whichApplicationNamed" /> + <java-symbol type="string" name="whichApplicationLabel" /> <java-symbol type="string" name="whichViewApplication" /> <java-symbol type="string" name="whichViewApplicationNamed" /> + <java-symbol type="string" name="whichViewApplicationLabel" /> <java-symbol type="string" name="whichEditApplication" /> <java-symbol type="string" name="whichEditApplicationNamed" /> + <java-symbol type="string" name="whichEditApplicationLabel" /> <java-symbol type="string" name="whichSendApplication" /> <java-symbol type="string" name="whichSendApplicationNamed" /> + <java-symbol type="string" name="whichSendApplicationLabel" /> <java-symbol type="string" name="whichSendToApplication" /> <java-symbol type="string" name="whichSendToApplicationNamed" /> + <java-symbol type="string" name="whichSendToApplicationLabel" /> + <java-symbol type="string" name="whichImageCaptureApplication" /> + <java-symbol type="string" name="whichImageCaptureApplicationNamed" /> + <java-symbol type="string" name="whichImageCaptureApplicationLabel" /> <java-symbol type="attr" name="lightY" /> <java-symbol type="attr" name="lightZ" /> <java-symbol type="attr" name="lightRadius" /> @@ -2238,6 +2243,7 @@ <java-symbol type="array" name="networks_not_clear_data" /> <java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" /> <java-symbol type="string" name="whichHomeApplicationNamed" /> + <java-symbol type="string" name="whichHomeApplicationLabel" /> <java-symbol type="bool" name="config_sms_force_7bit_encoding" /> <java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" /> <java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" /> @@ -2496,6 +2502,8 @@ <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" /> <java-symbol type="layout" name="app_anr_dialog" /> + <java-symbol type="layout" name="notification_template_material_messaging" /> + <java-symbol type="id" name="aerr_wait" /> <java-symbol type="id" name="notification_content_container" /> @@ -2525,11 +2533,34 @@ <java-symbol type="string" name="carrier_app_notification_text" /> <java-symbol type="string" name="negative_duration" /> + <java-symbol type="dimen" name="notification_messaging_spacing" /> + <!-- WallpaperManager config --> <java-symbol type="string" name="config_wallpaperCropperPackage" /> <java-symbol type="id" name="textSpacerNoTitle" /> <java-symbol type="id" name="titleDividerNoCustom" /> + <java-symbol type="id" name="notification_messaging" /> + <java-symbol type="bool" name="config_sustainedPerformanceModeSupported" /> + + <!-- Wearable input extract edit view --> + <java-symbol type="drawable" name="ic_input_extract_action_go" /> + <java-symbol type="drawable" name="ic_input_extract_action_search" /> + <java-symbol type="drawable" name="ic_input_extract_action_send" /> + <java-symbol type="drawable" name="ic_input_extract_action_next" /> + <java-symbol type="drawable" name="ic_input_extract_action_done" /> + <java-symbol type="drawable" name="ic_input_extract_action_previous" /> + <java-symbol type="drawable" name="ic_input_extract_action_return" /> + + <java-symbol type="fraction" name="input_extract_layout_height" /> + <java-symbol type="fraction" name="input_extract_layout_padding_left" /> + <java-symbol type="fraction" name="input_extract_layout_padding_left_no_action" /> + <java-symbol type="fraction" name="input_extract_layout_padding_right" /> + <java-symbol type="fraction" name="input_extract_text_margin_bottom" /> + <java-symbol type="fraction" name="input_extract_action_margin_bottom" /> + + <java-symbol type="dimen" name="input_extract_action_button_width" /> + <java-symbol type="dimen" name="input_extract_action_button_height" /> </resources> diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml index 478d66c767c0..25a6e006c031 100644 --- a/core/res/res/values/themes_micro.xml +++ b/core/res/res/values/themes_micro.xml @@ -83,4 +83,18 @@ <item name="fontFamily">sans-serif-condensed-light</item> <item name="textColor">@color/micro_text_light</item> </style> + + <style name="Theme.Micro.Panel" parent="Theme.Material.Panel" /> + <style name="Theme.Micro.Light.Panel" parent="Theme.Material.Light.Panel" /> + + <!-- Default theme for material style input methods, which is used by the + {@link android.inputmethodservice.InputMethodService} class. + This inherits from Theme.Panel, but sets up IME appropriate animations + and a few custom attributes. --> + <style name="Theme.Micro.InputMethod" parent="Theme.Micro.Panel"> + <item name="windowAnimationStyle">@style/Animation.InputMethod</item> + <item name="imeFullscreenBackground">#1e282c</item> + <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item> + <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item> + </style> </resources> diff --git a/core/res/res/xml/eri.xml b/core/res/res/xml/eri.xml deleted file mode 100644 index cd66f1447a59..000000000000 --- a/core/res/res/xml/eri.xml +++ /dev/null @@ -1,118 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** 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. -*/ ---> - -<!-- Note that IconMode can be only 0, ON or 1, FLASHING - The icon is turned OFF if then IconIndex = 1 --> - -<EriFile VersionNumber="1357" - NumberOfEriEntries="12" - EriFileType="1"> - - <CallPromptId Id="0" - CallPromptText="CallPromptId0"/> - - <CallPromptId Id="1" - CallPromptText="CallPromptId1"/> - - <CallPromptId Id="2" - CallPromptText="CallPromptId2"/> - - <EriInfo RoamingIndicator="64" - IconIndex="1" - IconMode="0" - EriText="T-CDMA 64" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="65" - IconIndex="65" - IconMode="0" - EriText="T-CDMA 65" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="66" - IconIndex="1" - IconMode="0" - EriText="T-CDMA Ext 66" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="67" - IconIndex="67" - IconMode="0" - EriText="T-CDMA Ext 67" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="68" - IconIndex="68" - IconMode="0" - EriText="T-CDMA Roam 68" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="69" - IconIndex="69" - IconMode="1" - EriText="T-CDMA Ext 69" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="70" - IconIndex="70" - IconMode="1" - EriText="T-CDMA Roam 70" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="71" - IconIndex="1" - IconMode="0" - EriText="T-CDMA Ext 71" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="72" - IconIndex="72" - IconMode="0" - EriText="T-CDMA Ext 72" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="73" - IconIndex="73" - IconMode="0" - EriText="T-CDMA Roam 73" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="74" - IconIndex="74" - IconMode="1" - EriText="T-CDMA Ext 74" - CallPromptId="0" - AlertId="0"/> - - <EriInfo RoamingIndicator="75" - IconIndex="75" - IconMode="1" - EriText="T-CDMA Roam 75" - CallPromptId="0" - AlertId="0"/> - -</EriFile> diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java new file mode 100644 index 000000000000..fd57baa217b0 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package com.android.internal.app.procstats; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; + +import android.os.BatteryStats; +import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.mockito.Mockito; + +/** + * Provides test cases for SparseMappingTable. + */ +public class SparseMappingTableTest extends TestCase { + private static final String TAG = "SparseMappingTableTest"; + + final byte ID1 = 1; + final byte ID2 = 2; + + final long VALUE1 = 100; + final long VALUE2 = 10000000000L; + + /** + * Test the parceling and unparceling logic when there is no data. + */ + @SmallTest + public void testParcelingEmpty() throws Exception { + final SparseMappingTable data = new SparseMappingTable(); + final SparseMappingTable.Table table = new SparseMappingTable.Table(data); + + final Parcel dataParcel = Parcel.obtain(); + data.writeToParcel(dataParcel); + + final Parcel tableParcel = Parcel.obtain(); + table.writeToParcel(tableParcel); + + dataParcel.setDataPosition(0); + final SparseMappingTable data1 = new SparseMappingTable(); + data1.readFromParcel(dataParcel); + Assert.assertEquals(0, dataParcel.dataAvail()); + dataParcel.recycle(); + + tableParcel.setDataPosition(0); + final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); + table1.readFromParcel(tableParcel); + Assert.assertEquals(0, tableParcel.dataAvail()); + tableParcel.recycle(); + } + + /** + * Test the parceling and unparceling logic. + */ + @SmallTest + public void testParceling() throws Exception { + int key; + final SparseMappingTable data = new SparseMappingTable(); + final SparseMappingTable.Table table = new SparseMappingTable.Table(data); + + key = table.getOrAddKey(ID1, 1); + table.setValue(key, VALUE1); + + key = table.getOrAddKey(ID2, 1); + table.setValue(key, VALUE2); + + final Parcel dataParcel = Parcel.obtain(); + data.writeToParcel(dataParcel); + + final Parcel tableParcel = Parcel.obtain(); + table.writeToParcel(tableParcel); + + dataParcel.setDataPosition(0); + final SparseMappingTable data1 = new SparseMappingTable(); + data1.readFromParcel(dataParcel); + Assert.assertEquals(0, dataParcel.dataAvail()); + dataParcel.recycle(); + + tableParcel.setDataPosition(0); + final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); + table1.readFromParcel(tableParcel); + Assert.assertEquals(0, tableParcel.dataAvail()); + tableParcel.recycle(); + + key = table1.getKey(ID1); + Assert.assertEquals(VALUE1, table1.getValue(key)); + + key = table1.getKey(ID2); + Assert.assertEquals(VALUE2, table1.getValue(key)); + } + + + /** + * Test that after resetting you can still read data, you just get no values. + */ + @SmallTest + public void testParcelingWithReset() throws Exception { + int key; + final SparseMappingTable data = new SparseMappingTable(); + final SparseMappingTable.Table table = new SparseMappingTable.Table(data); + + key = table.getOrAddKey(ID1, 1); + table.setValue(key, VALUE1); + + data.reset(); + table.resetTable(); + + key = table.getOrAddKey(ID2, 1); + table.setValue(key, VALUE2); + + Log.d(TAG, "before: " + data.dumpInternalState(true)); + Log.d(TAG, "before: " + table.dumpInternalState()); + + final Parcel dataParcel = Parcel.obtain(); + data.writeToParcel(dataParcel); + + final Parcel tableParcel = Parcel.obtain(); + table.writeToParcel(tableParcel); + + dataParcel.setDataPosition(0); + final SparseMappingTable data1 = new SparseMappingTable(); + data1.readFromParcel(dataParcel); + Assert.assertEquals(0, dataParcel.dataAvail()); + dataParcel.recycle(); + + tableParcel.setDataPosition(0); + final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); + table1.readFromParcel(tableParcel); + Assert.assertEquals(0, tableParcel.dataAvail()); + tableParcel.recycle(); + + key = table1.getKey(ID1); + Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); + + key = table1.getKey(ID2); + Assert.assertEquals(VALUE2, table1.getValue(key)); + + Log.d(TAG, " after: " + data1.dumpInternalState(true)); + Log.d(TAG, " after: " + table1.dumpInternalState()); + } + + /** + * Test that it fails if you reset the data and not the table. + * + * Resetting the table and not the data is basically okay. The data in the + * SparseMappingTable will be leaked. + */ + @SmallTest + public void testResetDataOnlyFails() throws Exception { + int key; + final SparseMappingTable data = new SparseMappingTable(); + final SparseMappingTable.Table table = new SparseMappingTable.Table(data); + + key = table.getOrAddKey(ID1, 1); + table.setValue(key, VALUE1); + + Assert.assertEquals(VALUE1, table.getValue(key)); + + data.reset(); + + try { + table.getValue(key); + throw new Exception("Exception not thrown after mismatched reset calls."); + } catch (RuntimeException ex) { + // Good + } + } + + /** + * Test that trying to get data that you didn't add fails correctly. + */ + @SmallTest + public void testInvalidKey() throws Exception { + int key; + final SparseMappingTable data = new SparseMappingTable(); + final SparseMappingTable.Table table = new SparseMappingTable.Table(data); + + key = table.getKey(ID1); + + // The key should be INVALID_KEY + Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); + + // If you get the value with getValueForId you get 0. + Assert.assertEquals(0, table.getValueForId(ID1)); + } +} + + + diff --git a/data/etc/platform.xml b/data/etc/platform.xml index d412d7c5aa33..8a7d39b65edd 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -111,6 +111,20 @@ <group gid="media" /> </permission> + <!-- These are permissions that were mapped to gids but we need + to keep them here until an upgrade from L to the current + version is to be supported. These permissions are built-in + and in L were not stored in packages.xml as a result if they + are not defined here while parsing packages.xml we would + ignore these permissions being granted to apps and not + propagate the granted state. From N we are storing the + built-in permissions in packages.xml as the saved storage + is negligible (one tag with the permission) compared to + the fragility as one can remove a built-in permission which + no longer needs to be mapped to gids and break grant propagation. --> + <permission name="android.permission.READ_EXTERNAL_STORAGE" /> + <permission name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <!-- ================================================================== --> <!-- ================================================================== --> <!-- ================================================================== --> diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd index 5600b5c5c469..887b4eabe2b7 100644 --- a/docs/html/guide/topics/manifest/application-element.jd +++ b/docs/html/guide/topics/manifest/application-element.jd @@ -472,6 +472,8 @@ from {@link android.content.pm.ApplicationInfo#flags ApplicationInfo.flags} or {@link android.os.StrictMode.VmPolicy.Builder#detectCleartextNetwork() StrictMode.VmPolicy.Builder.detectCleartextNetwork()}. <p>This attribute was added in API level 23.</p> + +<p>This flag is ignored on Android N and above if an Android Network Security Config is present.</p> </dd> <dt><a name="vmSafeMode"></a>{@code android:vmSafeMode}</dt> diff --git a/graphics/java/android/graphics/PixelCopy.java b/graphics/java/android/graphics/PixelCopy.java new file mode 100644 index 000000000000..c5991264e555 --- /dev/null +++ b/graphics/java/android/graphics/PixelCopy.java @@ -0,0 +1,104 @@ +package android.graphics; + +import android.annotation.NonNull; +import android.os.Handler; +import android.view.Surface; +import android.view.SurfaceView; +import android.view.ThreadedRenderer; + +/** + * Provides a mechanisms to issue pixel copy requests to allow for copy + * operations from {@link Surface} to {@link Bitmap} + * + * @hide + */ +public final class PixelCopy { + /** + * Contains the result of a pixel copy request + */ + public static final class Response { + /** + * Indicates whether or not the copy request completed successfully. + * If this is true, then {@link #bitmap} contains the result of the copy. + * If this is false, {@link #bitmap} is unmodified from the originally + * passed destination. + * + * For example a request might fail if the source is protected content + * so copies are not allowed. Similarly if the source has nothing to + * copy from, because either no frames have been produced yet or because + * it has already been destroyed, then this will be false. + */ + public boolean success; + + /** + * The output bitmap. This is always the same object that was passed + * to request() as the 'dest' bitmap. If {@link #success} is true this + * contains a copy of the pixels of the source object. If {@link #success} + * is false then this is unmodified. + */ + @NonNull + public Bitmap bitmap; + } + + public interface OnPixelCopyFinished { + /** + * Callback for when a pixel copy request has completed. This will be called + * regardless of whether the copy succeeded or failed. + * + * @param response Contains the result of the copy request which includes + * whether or not the copy was successful. + */ + void onPixelCopyFinished(PixelCopy.Response response); + } + + /** + * Requests for the display content of a {@link SurfaceView} to be copied + * into a provided {@link Bitmap}. + * + * The contents of the source will be scaled to fit exactly inside the bitmap. + * The pixel format of the source buffer will be converted, as part of the copy, + * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer + * in the SurfaceView's Surface will be used as the source of the copy. + * + * @param source The source from which to copy + * @param dest The destination of the copy. The source will be scaled to + * match the width, height, and format of this bitmap. + * @param listener Callback for when the pixel copy request completes + * @param listenerThread The callback will be invoked on this Handler when + * the copy is finished. + */ + public static void request(@NonNull SurfaceView source, @NonNull Bitmap dest, + @NonNull OnPixelCopyFinished listener, @NonNull Handler listenerThread) { + request(source.getHolder().getSurface(), dest, listener, listenerThread); + } + + /** + * Requests a copy of the pixels from a {@link Surface} to be copied into + * a provided {@link Bitmap}. + * + * The contents of the source will be scaled to fit exactly inside the bitmap. + * The pixel format of the source buffer will be converted, as part of the copy, + * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer + * in the Surface will be used as the source of the copy. + * + * @param source The source from which to copy + * @param dest The destination of the copy. The source will be scaled to + * match the width, height, and format of this bitmap. + * @param listener Callback for when the pixel copy request completes + * @param listenerThread The callback will be invoked on this Handler when + * the copy is finished. + */ + public static void request(@NonNull Surface source, @NonNull Bitmap dest, + @NonNull OnPixelCopyFinished listener, @NonNull Handler listenerThread) { + // TODO: Make this actually async and fast and cool and stuff + final PixelCopy.Response response = new PixelCopy.Response(); + response.success = ThreadedRenderer.copySurfaceInto(source, dest); + response.bitmap = dest; + listenerThread.post(new Runnable() { + @Override + public void run() { + listener.onPixelCopyFinished(response); + } + }); + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index f15aff7de39c..2886f0dd4a2e 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -19,6 +19,7 @@ package android.graphics; import android.content.res.AssetManager; import android.util.Log; import android.util.LongSparseArray; +import android.util.LruCache; import android.util.SparseArray; import org.xmlpull.v1.XmlPullParserException; @@ -63,6 +64,11 @@ public class Typeface { private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = new LongSparseArray<SparseArray<Typeface>>(3); + /** + * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16. + */ + private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16); + static Typeface sDefaultTypeface; static Map<String, Typeface> sSystemFontMap; static FontFamily[] sFallbackFonts; @@ -176,22 +182,50 @@ public class Typeface { /** * Create a new typeface from the specified font data. - * @param mgr The application's asset manager - * @param path The file name of the font data in the assets directory + * + * @param mgr The application's asset manager + * @param path The file name of the font data in the assets directory * @return The new typeface. */ public static Typeface createFromAsset(AssetManager mgr, String path) { if (sFallbackFonts != null) { - FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFontFromAsset(mgr, path)) { - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families); + synchronized (sDynamicTypefaceCache) { + final String key = createAssetUid(mgr, path); + Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; + + FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAsset(mgr, path)) { + FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } } } throw new RuntimeException("Font asset not found " + path); } /** + * Creates a unique id for a given AssetManager and asset path. + * + * @param mgr AssetManager instance + * @param path The path for the asset. + * @return Unique id for a given AssetManager and asset path. + */ + private static String createAssetUid(final AssetManager mgr, String path) { + final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers(); + final StringBuilder builder = new StringBuilder(); + final int size = pkgs.size(); + for (int i = 0; i < size; i++) { + builder.append(pkgs.valueAt(i)); + builder.append("-"); + } + builder.append(path); + return builder.toString(); + } + + /** * Create a new typeface from the specified font file. * * @param path The path to the font data. diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index e75fb9870e0b..0e457800aac9 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -534,13 +534,17 @@ public class VectorDrawable extends Drawable { public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { - if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererRefBase != null) { + if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) { // This VD has been used to display other VD resource content, clean up. + if (mVectorState.mRootGroup != null) { + // Remove child nodes' reference to tree + mVectorState.mRootGroup.setTree(null); + } mVectorState.mRootGroup = new VGroup(); - if (mVectorState.mNativeRendererRefBase != null) { - mVectorState.mNativeRendererRefBase.release(); + if (mVectorState.mNativeTree != null) { + mVectorState.mNativeTree.release(); } - mVectorState.createNativeRenderer(mVectorState.mRootGroup.mNativePtr); + mVectorState.createNativeTree(mVectorState.mRootGroup); } final VectorDrawableState state = mVectorState; state.setDensity(Drawable.resolveDensity(r, 0)); @@ -734,7 +738,7 @@ public class VectorDrawable extends Drawable { Insets mOpticalInsets = Insets.NONE; String mRootName = null; VGroup mRootGroup; - VirtualRefBasePtr mNativeRendererRefBase = null; + VirtualRefBasePtr mNativeTree = null; int mDensity = DisplayMetrics.DENSITY_DEFAULT; final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>(); @@ -755,7 +759,7 @@ public class VectorDrawable extends Drawable { mTintMode = copy.mTintMode; mAutoMirrored = copy.mAutoMirrored; mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap); - createNativeRenderer(mRootGroup.mNativePtr); + createNativeTree(mRootGroup); mBaseWidth = copy.mBaseWidth; mBaseHeight = copy.mBaseHeight; @@ -770,15 +774,16 @@ public class VectorDrawable extends Drawable { } } - private void createNativeRenderer(long rootGroupPtr) { - mNativeRendererRefBase = new VirtualRefBasePtr(nCreateRenderer(rootGroupPtr)); + private void createNativeTree(VGroup rootGroup) { + mNativeTree = new VirtualRefBasePtr(nCreateTree(rootGroup.mNativePtr)); + mRootGroup.setTree(mNativeTree); } long getNativeRenderer() { - if (mNativeRendererRefBase == null) { + if (mNativeTree == null) { return 0; } - return mNativeRendererRefBase.get(); + return mNativeTree.get(); } public boolean canReuseCache() { @@ -817,7 +822,7 @@ public class VectorDrawable extends Drawable { public VectorDrawableState() { mRootGroup = new VGroup(); - createNativeRenderer(mRootGroup.mNativePtr); + createNativeTree(mRootGroup); } @Override @@ -881,16 +886,16 @@ public class VectorDrawable extends Drawable { * has changed. */ public boolean setAlpha(float alpha) { - return nSetRootAlpha(mNativeRendererRefBase.get(), alpha); + return nSetRootAlpha(mNativeTree.get(), alpha); } @SuppressWarnings("unused") public float getAlpha() { - return nGetRootAlpha(mNativeRendererRefBase.get()); + return nGetRootAlpha(mNativeTree.get()); } } - static class VGroup implements VObject { + static class VGroup extends VObject { private static final int ROTATE_INDEX = 0; private static final int PIVOT_X_INDEX = 1; private static final int PIVOT_Y_INDEX = 2; @@ -984,11 +989,18 @@ public class VectorDrawable extends Drawable { public void addChild(VObject child) { nAddChild(mNativePtr, child.getNativePtr()); mChildren.add(child); - mIsStateful |= child.isStateful(); } @Override + public void setTree(VirtualRefBasePtr treeRoot) { + super.setTree(treeRoot); + for (int i = 0; i < mChildren.size(); i++) { + mChildren.get(i).setTree(treeRoot); + } + } + + @Override public long getNativePtr() { return mNativePtr; } @@ -1101,79 +1113,93 @@ public class VectorDrawable extends Drawable { /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ @SuppressWarnings("unused") public float getRotation() { - return nGetRotation(mNativePtr); + return isTreeValid() ? nGetRotation(mNativePtr) : 0; } @SuppressWarnings("unused") public void setRotation(float rotation) { - nSetRotation(mNativePtr, rotation); + if (isTreeValid()) { + nSetRotation(mNativePtr, rotation); + } } @SuppressWarnings("unused") public float getPivotX() { - return nGetPivotX(mNativePtr); + return isTreeValid() ? nGetPivotX(mNativePtr) : 0; } @SuppressWarnings("unused") public void setPivotX(float pivotX) { - nSetPivotX(mNativePtr, pivotX); + if (isTreeValid()) { + nSetPivotX(mNativePtr, pivotX); + } } @SuppressWarnings("unused") public float getPivotY() { - return nGetPivotY(mNativePtr); + return isTreeValid() ? nGetPivotY(mNativePtr) : 0; } @SuppressWarnings("unused") public void setPivotY(float pivotY) { - nSetPivotY(mNativePtr, pivotY); + if (isTreeValid()) { + nSetPivotY(mNativePtr, pivotY); + } } @SuppressWarnings("unused") public float getScaleX() { - return nGetScaleX(mNativePtr); + return isTreeValid() ? nGetScaleX(mNativePtr) : 0; } @SuppressWarnings("unused") public void setScaleX(float scaleX) { - nSetScaleX(mNativePtr, scaleX); + if (isTreeValid()) { + nSetScaleX(mNativePtr, scaleX); + } } @SuppressWarnings("unused") public float getScaleY() { - return nGetScaleY(mNativePtr); + return isTreeValid() ? nGetScaleY(mNativePtr) : 0; } @SuppressWarnings("unused") public void setScaleY(float scaleY) { - nSetScaleY(mNativePtr, scaleY); + if (isTreeValid()) { + nSetScaleY(mNativePtr, scaleY); + } } @SuppressWarnings("unused") public float getTranslateX() { - return nGetTranslateX(mNativePtr); + return isTreeValid() ? nGetTranslateX(mNativePtr) : 0; } @SuppressWarnings("unused") public void setTranslateX(float translateX) { - nSetTranslateX(mNativePtr, translateX); + if (isTreeValid()) { + nSetTranslateX(mNativePtr, translateX); + } } @SuppressWarnings("unused") public float getTranslateY() { - return nGetTranslateY(mNativePtr); + return isTreeValid() ? nGetTranslateY(mNativePtr) : 0; } @SuppressWarnings("unused") public void setTranslateY(float translateY) { - nSetTranslateY(mNativePtr, translateY); + if (isTreeValid()) { + nSetTranslateY(mNativePtr, translateY); + } } } /** * Common Path information for clip path and normal path. */ - static abstract class VPath implements VObject { + static abstract class VPath extends VObject { protected PathParser.PathData mPathData = null; String mPathName; @@ -1203,7 +1229,9 @@ public class VectorDrawable extends Drawable { @SuppressWarnings("unused") public void setPathData(PathParser.PathData pathData) { mPathData.setPathData(pathData); - nSetPathData(getNativePtr(), mPathData.getNativePtr()); + if (isTreeValid()) { + nSetPathData(getNativePtr(), mPathData.getNativePtr()); + } } } @@ -1549,97 +1577,120 @@ public class VectorDrawable extends Drawable { /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ @SuppressWarnings("unused") int getStrokeColor() { - return nGetStrokeColor(mNativePtr); + return isTreeValid() ? nGetStrokeColor(mNativePtr) : 0; } @SuppressWarnings("unused") void setStrokeColor(int strokeColor) { mStrokeColors = null; - nSetStrokeColor(mNativePtr, strokeColor); + if (isTreeValid()) { + nSetStrokeColor(mNativePtr, strokeColor); + } } @SuppressWarnings("unused") float getStrokeWidth() { - return nGetStrokeWidth(mNativePtr); + return isTreeValid() ? nGetStrokeWidth(mNativePtr) : 0; } @SuppressWarnings("unused") void setStrokeWidth(float strokeWidth) { - nSetStrokeWidth(mNativePtr, strokeWidth); + if (isTreeValid()) { + nSetStrokeWidth(mNativePtr, strokeWidth); + } } @SuppressWarnings("unused") float getStrokeAlpha() { - return nGetStrokeAlpha(mNativePtr); + return isTreeValid() ? nGetStrokeAlpha(mNativePtr) : 0; } @SuppressWarnings("unused") void setStrokeAlpha(float strokeAlpha) { - nSetStrokeAlpha(mNativePtr, strokeAlpha); + if (isTreeValid()) { + nSetStrokeAlpha(mNativePtr, strokeAlpha); + } } @SuppressWarnings("unused") int getFillColor() { - return nGetFillColor(mNativePtr); + return isTreeValid() ? nGetFillColor(mNativePtr) : 0; } @SuppressWarnings("unused") void setFillColor(int fillColor) { mFillColors = null; - nSetFillColor(mNativePtr, fillColor); + if (isTreeValid()) { + nSetFillColor(mNativePtr, fillColor); + } } @SuppressWarnings("unused") float getFillAlpha() { - return nGetFillAlpha(mNativePtr); + return isTreeValid() ? nGetFillAlpha(mNativePtr) : 0; } @SuppressWarnings("unused") void setFillAlpha(float fillAlpha) { - nSetFillAlpha(mNativePtr, fillAlpha); + if (isTreeValid()) { + nSetFillAlpha(mNativePtr, fillAlpha); + } } @SuppressWarnings("unused") float getTrimPathStart() { - return nGetTrimPathStart(mNativePtr); + return isTreeValid() ? nGetTrimPathStart(mNativePtr) : 0; } @SuppressWarnings("unused") void setTrimPathStart(float trimPathStart) { - nSetTrimPathStart(mNativePtr, trimPathStart); + if (isTreeValid()) { + nSetTrimPathStart(mNativePtr, trimPathStart); + } } @SuppressWarnings("unused") float getTrimPathEnd() { - return nGetTrimPathEnd(mNativePtr); + return isTreeValid() ? nGetTrimPathEnd(mNativePtr) : 0; } @SuppressWarnings("unused") void setTrimPathEnd(float trimPathEnd) { - nSetTrimPathEnd(mNativePtr, trimPathEnd); + if (isTreeValid()) { + nSetTrimPathEnd(mNativePtr, trimPathEnd); + } } @SuppressWarnings("unused") float getTrimPathOffset() { - return nGetTrimPathOffset(mNativePtr); + return isTreeValid() ? nGetTrimPathOffset(mNativePtr) : 0; } @SuppressWarnings("unused") void setTrimPathOffset(float trimPathOffset) { - nSetTrimPathOffset(mNativePtr, trimPathOffset); + if (isTreeValid()) { + nSetTrimPathOffset(mNativePtr, trimPathOffset); + } } } - interface VObject { - long getNativePtr(); - void inflate(Resources r, AttributeSet attrs, Theme theme); - boolean canApplyTheme(); - void applyTheme(Theme t); - boolean onStateChange(int[] state); - boolean isStateful(); + abstract static class VObject { + VirtualRefBasePtr mTreePtr = null; + boolean isTreeValid() { + return mTreePtr != null && mTreePtr.get() != 0; + } + void setTree(VirtualRefBasePtr ptr) { + mTreePtr = ptr; + } + abstract long getNativePtr(); + abstract void inflate(Resources r, AttributeSet attrs, Theme theme); + abstract boolean canApplyTheme(); + abstract void applyTheme(Theme t); + abstract boolean onStateChange(int[] state); + abstract boolean isStateful(); } - private static native long nCreateRenderer(long rootGroupPtr); + private static native long nCreateTree(long rootGroupPtr); private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth, float viewportHeight); private static native boolean nSetRootAlpha(long rendererPtr, float alpha); diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 0606b0b1a158..717a1e6eacc4 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -84,6 +84,7 @@ hwui_src_files := \ Properties.cpp \ PropertyValuesHolder.cpp \ PropertyValuesAnimatorSet.cpp \ + Readback.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ RenderProperties.cpp \ diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index d1ff67027d07..9d4ecccef4ab 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -285,6 +285,7 @@ void JankTracker::dumpData(const ProfileData* data, int fd) { void JankTracker::reset() { mData->jankTypeCounts.fill(0); mData->frameCounts.fill(0); + mData->slowFrameCounts.fill(0); mData->totalFrameCount = 0; mData->jankFrameCount = 0; mData->statStartTime = systemTime(CLOCK_MONOTONIC); diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp new file mode 100644 index 000000000000..d7df77c2f3ed --- /dev/null +++ b/libs/hwui/Readback.cpp @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#include "Readback.h" + +#include "Caches.h" +#include "Image.h" +#include "GlopBuilder.h" +#include "renderstate/RenderState.h" +#include "renderthread/EglManager.h" +#include "utils/GLUtils.h" + +#include <GLES2/gl2.h> +#include <ui/Fence.h> +#include <ui/GraphicBuffer.h> + +namespace android { +namespace uirenderer { + +bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, + Surface& surface, SkBitmap* bitmap) { + // TODO: Clean this up and unify it with LayerRenderer::copyLayer, + // of which most of this is copied from. + renderThread.eglManager().initialize(); + + Caches& caches = Caches::getInstance(); + RenderState& renderState = renderThread.renderState(); + int destWidth = bitmap->width(); + int destHeight = bitmap->height(); + if (destWidth > caches.maxTextureSize + || destHeight > caches.maxTextureSize) { + ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", + destWidth, destHeight, caches.maxTextureSize); + return false; + } + GLuint fbo = renderState.createFramebuffer(); + if (!fbo) { + ALOGW("Could not obtain an FBO"); + return false; + } + + SkAutoLockPixels alp(*bitmap); + + GLuint texture; + + GLenum format; + GLenum type; + + switch (bitmap->colorType()) { + case kAlpha_8_SkColorType: + format = GL_ALPHA; + type = GL_UNSIGNED_BYTE; + break; + case kRGB_565_SkColorType: + format = GL_RGB; + type = GL_UNSIGNED_SHORT_5_6_5; + break; + case kARGB_4444_SkColorType: + format = GL_RGBA; + type = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case kN32_SkColorType: + default: + format = GL_RGBA; + type = GL_UNSIGNED_BYTE; + break; + } + + renderState.bindFramebuffer(fbo); + + // TODO: Use layerPool or something to get this maybe? But since we + // need explicit format control we can't currently. + + // Setup the rendertarget + glGenTextures(1, &texture); + caches.textureState().activateTexture(0); + caches.textureState().bindTexture(texture); + glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, format, destWidth, destHeight, + 0, format, type, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture, 0); + + // Setup the source + sp<GraphicBuffer> sourceBuffer; + sp<Fence> sourceFence; + // FIXME: Waiting on an API from libgui for this + // surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence); + if (!sourceBuffer.get()) { + ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); + return false; + } + int err = sourceFence->wait(500 /* ms */); + if (err != NO_ERROR) { + ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); + return false; + } + Image sourceImage(sourceBuffer); + if (!sourceImage.getTexture()) { + ALOGW("Failed to make an EGLImage from the GraphicBuffer"); + return false; + } + Texture sourceTexture(caches); + sourceTexture.wrap(sourceImage.getTexture(), + sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0 /* total lie */); + + { + // Draw & readback + renderState.setViewport(destWidth, destHeight); + renderState.scissor().setEnabled(false); + renderState.blend().syncEnabled(); + renderState.stencil().disable(); + + Rect destRect(destWidth, destHeight); + Glop glop; + GlopBuilder(renderState, caches, &glop) + .setRoundRectClipState(nullptr) + .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO + .setFillLayer(sourceTexture, nullptr, 1.0f, SkXfermode::kSrc_Mode, + Blend::ModeOrderSwap::NoSwap) + .setTransform(Matrix4::identity(), TransformFlags::None) + .setModelViewMapUnitToRect(destRect) + .build(); + Matrix4 ortho; + ortho.loadOrtho(destWidth, destHeight); + renderState.render(glop, ortho); + + glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, + type, bitmap->getPixels()); + } + + // Cleanup + caches.textureState().deleteTexture(texture); + renderState.deleteFramebuffer(fbo); + + GL_CHECKPOINT(MODERATE); + + return true; +} + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h new file mode 100644 index 000000000000..ea03c829f492 --- /dev/null +++ b/libs/hwui/Readback.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#pragma once + +#include "renderthread/RenderThread.h" + +#include <SkBitmap.h> +#include <gui/Surface.h> + +namespace android { +namespace uirenderer { + +class Readback { +public: + static bool copySurfaceInto(renderthread::RenderThread& renderThread, + Surface& surface, SkBitmap* bitmap); +}; + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 1116383e4eab..096093caff51 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -19,6 +19,7 @@ #include "DeferredLayerUpdater.h" #include "DisplayList.h" #include "LayerRenderer.h" +#include "Readback.h" #include "Rect.h" #include "renderthread/CanvasContext.h" #include "renderthread/RenderTask.h" @@ -604,6 +605,20 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) { post(task); } +CREATE_BRIDGE3(copySurfaceInto, RenderThread* thread, + Surface* surface, SkBitmap* bitmap) { + return (void*) Readback::copySurfaceInto(*args->thread, + *args->surface, args->bitmap); +} + +bool RenderProxy::copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap) { + SETUP_TASK(copySurfaceInto); + args->bitmap = bitmap; + args->surface = surface.get(); + args->thread = &RenderThread::getInstance(); + return (bool) staticPostAndWait(task); +} + void RenderProxy::post(RenderTask* task) { mRenderThread.queue(task); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index ecc296b4738e..98aace0da6b5 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -126,6 +126,8 @@ public: ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer); ANDROID_API long getDroppedFrameReportCount(); + ANDROID_API static bool copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap); + private: RenderThread& mRenderThread; CanvasContext* mContext; diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index a5550ec7248b..4504e699b38d 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -876,22 +876,24 @@ public class AudioRecord implements AudioRouting * Calling {@link #startRecording()} following a {@link #stop()} will reset * the frame count to 0. * - * @param timestamp a reference to a non-null AudioTimestamp instance. + * @param outTimestamp a caller provided non-null AudioTimestamp instance, + * which is updated with the AudioRecord frame delivery information upon success. * @param timebase one of * {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or - * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}. + * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}, + * used to select the clock for the AudioTimestamp time. * @return {@link #SUCCESS} if a timestamp is available, * or {@link #ERROR_INVALID_OPERATION} if a timestamp not available. */ - public int getTimestamp(@NonNull AudioTimestamp timestamp, + public int getTimestamp(@NonNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase) { - if (timestamp == null || + if (outTimestamp == null || (timebase != AudioTimestamp.TIMEBASE_BOOTTIME && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) { throw new IllegalArgumentException(); } - return native_get_timestamp(timestamp, timebase); + return native_get_timestamp(outTimestamp, timebase); } /** @@ -1725,7 +1727,7 @@ public class AudioRecord implements AudioRouting private native final void native_enableDeviceCallback(); private native final void native_disableDeviceCallback(); - private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp, + private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase); //--------------------------------------------------------- diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 03dc6995c798..0b648765cafa 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -369,8 +369,7 @@ public final class TvInputInfo implements Parcelable { } /** - * Returns the extras associated with this TV input. - * @hide + * Returns domain-specific extras associated with this TV input. */ public Bundle getExtras() { return mExtras; @@ -847,11 +846,12 @@ public final class TvInputInfo implements Parcelable { } /** - * Sets the extras associated with this TV input. + * Sets domain-specific extras associated with this TV input. * - * @param extras The extras associated with this TV input. + * @param extras Domain-specific extras associated with this TV input. Keys <em>must</em> be + * a scoped name, i.e. prefixed with a package name you own, so that different + * developers will not create conflicting keys. * @return This Builder object to allow for chaining of calls to builder methods. - * @hide */ public Builder setExtras(Bundle extras) { this.mExtras = extras; diff --git a/packages/DocumentsUI/res/color/item_root_icon.xml b/packages/DocumentsUI/res/color/item_root_icon.xml index 0aa2c1341db4..e1d7e61941ab 100644 --- a/packages/DocumentsUI/res/color/item_root_icon.xml +++ b/packages/DocumentsUI/res/color/item_root_icon.xml @@ -15,5 +15,10 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@*android:color/secondary_text_material_light" /> + <item + android:state_activated="false" + android:color="@*android:color/secondary_text_material_light" /> + <item + android:state_activated="true" + android:color="@color/root_activated_color" /> </selector> diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java index f6fe47bd908e..3373c23ed212 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java +++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java @@ -147,17 +147,13 @@ class NavigationView { } } - // Hamburger if drawer is present, else root icon, or sad nullness. + // Hamburger if drawer is present, else sad nullness. private @Nullable Drawable getActionBarIcon() { if (mDrawer.isPresent()) { return mToolbar.getContext().getDrawable(R.drawable.ic_hamburger); } else { - RootInfo root = mEnv.getCurrentRoot(); - if (root != null) { - return root.loadToolbarIcon(mToolbar.getContext()); - } + return null; } - return null; } void revealRootsDrawer(boolean open) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java index 8fcd9d1545c3..babde992a90b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java @@ -17,7 +17,6 @@ package com.android.documentsui; import static com.android.documentsui.Shared.DEBUG; -import static com.android.documentsui.Shared.TAG; import static com.android.documentsui.model.DocumentInfo.getCursorString; import android.content.ClipData; @@ -45,6 +44,8 @@ import java.util.List; * Provides support for gather a list of quick-viewable files into a quick view intent. */ final class QuickViewIntentBuilder { + + private static final String TAG = "QuickViewIntentBuilder"; private static final int MAX_CLIP_ITEMS = 1000; private final DocumentInfo mDocument; @@ -127,8 +128,18 @@ final class QuickViewIntentBuilder { for (int i = 0; i < siblingIds.length; i++) { cursor = mModel.getItem(siblingIds[i]); + if (cursor == null) { + if (DEBUG) Log.d(TAG, + "Unable to obtain cursor for sibling document, modelId: " + + siblingIds[i]); + continue; + } + mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); if (Document.MIME_TYPE_DIR.equals(mimeType)) { + if (DEBUG) Log.d(TAG, + "Skipping directory, not supported by quick view. modelId: " + + siblingIds[i]); continue; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index aa9f356f30bc..e7b2ed1782be 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -351,7 +351,10 @@ public class DirectoryFragment extends Fragment private boolean handleViewItem(String id) { final Cursor cursor = mModel.getItem(id); - assert(cursor != null); + if (cursor == null) { + Log.w(TAG, "Can't view item. Can't obtain cursor for modeId" + id); + return false; + } final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); @@ -465,11 +468,14 @@ public class DirectoryFragment extends Fragment public boolean onBeforeItemStateChange(String modelId, boolean selected) { if (selected) { final Cursor cursor = mModel.getItem(modelId); - - assert(cursor != null); + if (cursor == null) { + Log.w(TAG, "Can't obtain cursor for modelId: " + modelId); + return false; + } final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); + return mTuner.canSelectType(docMimeType, docFlags); } return true; @@ -479,7 +485,7 @@ public class DirectoryFragment extends Fragment public void onItemStateChanged(String modelId, boolean selected) { final Cursor cursor = mModel.getItem(modelId); if (cursor == null) { - Log.e(TAG, "Model returned null cursor for document: " + modelId + Log.w(TAG, "Model returned null cursor for document: " + modelId + ". Ignoring state changed event."); return; } @@ -1104,6 +1110,10 @@ public class DirectoryFragment extends Fragment List<String> enabled = new ArrayList<String>(); for (String id : mAdapter.getModelIds()) { Cursor cursor = getModel().getItem(id); + if (cursor != null) { + Log.w(TAG, "Skipping selection. Can't obtain cursor for modeId: " + id); + continue; + } String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); if (isDocumentEnabled(docMimeType, docFlags)) { @@ -1192,7 +1202,10 @@ public class DirectoryFragment extends Fragment String id = getModelId(v); if (id != null) { Cursor dstCursor = mModel.getItem(id); - assert(dstCursor != null); + if (dstCursor != null) { + Log.w(TAG, "Invalid destination. Can't obtain cursor for modelId: " + id); + return null; + } return DocumentInfo.fromDirectoryCursor(dstCursor); } @@ -1265,8 +1278,10 @@ public class DirectoryFragment extends Fragment } final Cursor cursor = mModel.getItem(modelId); - - assert(cursor != null); + if (cursor == null) { + Log.w(TAG, "Undraggable document. Can't obtain cursor for modelId " + modelId); + return Collections.EMPTY_LIST; + } return Lists.newArrayList( DocumentInfo.fromDirectoryCursor(cursor)); @@ -1395,7 +1410,7 @@ public class DirectoryFragment extends Fragment // Handle range selection adjustments. Extending the selection will adjust the // bounds of the in-progress range selection. Each time an unshifted navigation // event is received, the range selection is restarted. - if (shouldExtendSelection(event)) { + if (shouldExtendSelection(doc, event)) { if (!mSelectionManager.isRangeSelectionActive()) { // Start a range selection if one isn't active mSelectionManager.startRangeSelection(doc.getAdapterPosition()); @@ -1432,9 +1447,22 @@ public class DirectoryFragment extends Fragment return false; } - private boolean shouldExtendSelection(KeyEvent event) { - return Events.isNavigationKeyCode(event.getKeyCode()) && - event.isShiftPressed(); + private boolean shouldExtendSelection(DocumentHolder doc, KeyEvent event) { + if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) { + return false; + } + + // TODO: Combine this method with onBeforeItemStateChange, as both of them are almost + // the same, and responsible for the same thing (whether to select or not). + final Cursor cursor = mModel.getItem(doc.modelId); + if (cursor == null) { + Log.w(TAG, "Couldn't obtain cursor for modelId: " + doc.modelId); + return false; + } + + final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); + final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); + return mTuner.canSelectType(docMimeType, docFlags); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java index ac05c0570a46..f274df37f916 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java @@ -20,6 +20,7 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString; import android.annotation.Nullable; import android.content.Context; +import android.database.Cursor; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; @@ -476,9 +477,9 @@ class FocusManager implements View.OnFocusChangeListener { List<String> index = new ArrayList<>(itemCount); for (int i = 0; i < itemCount; i++) { String modelId = mAdapter.getModelId(i); - if (modelId != null) { - String title = - getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME); + Cursor cursor = mModel.getItem(modelId); + if (modelId != null && cursor != null) { + String title = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); // Perform case-insensitive search. index.add(title.toLowerCase()); } else { diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java index 3642b01bef59..e2a28ad9a782 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java @@ -37,6 +37,7 @@ import com.android.documentsui.dirlist.MultiSelectManager.Selection; import com.android.documentsui.model.DocumentInfo; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -403,11 +404,18 @@ public class Model { public @Nullable Cursor getItem(String modelId) { Integer pos = mPositions.get(modelId); - if (pos != null) { - mCursor.moveToPosition(pos); - return mCursor; + if (pos == null) { + if (DEBUG) Log.d(TAG, "Unabled to find cursor position for modelId: " + modelId); + return null; } - return null; + + if (!mCursor.moveToPosition(pos)) { + if (DEBUG) Log.d(TAG, + "Unabled to move cursor to position " + pos + " for modelId: " + modelId); + return null; + } + + return mCursor; } boolean isEmpty() { @@ -424,8 +432,11 @@ public class Model { final List<DocumentInfo> docs = new ArrayList<>(size); for (String modelId: items.getAll()) { final Cursor cursor = getItem(modelId); - assert(cursor != null); - + if (cursor == null) { + Log.w(TAG, + "Skipping document. Unabled to obtain cursor for modelId: " + modelId); + continue; + } docs.add(DocumentInfo.fromDirectoryCursor(cursor)); } return docs; diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java index 1285b34ce313..35d8988244f6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java @@ -378,8 +378,8 @@ public final class MultiSelectManager { * @param pos The anchor position for the selection range. */ void startRangeSelection(int pos) { - attemptSelect(mAdapter.getModelId(pos)); - setSelectionRangeBegin(pos); + attemptSelect(mAdapter.getModelId(pos)); + setSelectionRangeBegin(pos); } /** @@ -1268,6 +1268,11 @@ public final class MultiSelectManager { notifySelectionChanged(); } + @Override + public boolean onBeforeItemStateChange(String id, boolean nextState) { + return notifyBeforeItemStateChange(id, nextState); + } + private class ViewScroller implements Runnable { /** * The number of milliseconds of scrolling at which scroll speed continues to increase. @@ -1655,7 +1660,9 @@ public final class MultiSelectManager { if (id != null) { // The adapter inserts items for UI layout purposes that aren't associated // with files. Those will have a null model ID. Don't select them. - mSelection.add(id); + if (canSelect(id)) { + mSelection.add(id); + } } if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex, row, rowStartIndex, rowEndIndex)) { @@ -1669,6 +1676,21 @@ public final class MultiSelectManager { } /** + * @return True if the item is selectable. + */ + private boolean canSelect(String id) { + // TODO: Simplify the logic, so the check whether we can select is done in one place. + // Consider injecting FragmentTuner, or move the checks from MultiSelectManager to + // Selection. + for (OnSelectionChangedListener listener : mOnSelectionChangedListeners) { + if (!listener.onBeforeItemStateChange(id, true)) { + return false; + } + } + return true; + } + + /** * @return Returns true if the position is the nearest to the origin, or, in the case of the * lower-right corner, whether it is possible that the position is the nearest to the * origin. See comment below for reasoning for this special case. @@ -1700,6 +1722,7 @@ public final class MultiSelectManager { */ static interface OnSelectionChangedListener { public void onSelectionChanged(Set<String> updatedSelection); + public boolean onBeforeItemStateChange(String id, boolean nextState); } void addOnSelectionChangedListener(OnSelectionChangedListener listener) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java index 31ce8377ec76..3a86a51b2d18 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java @@ -139,11 +139,13 @@ public class DocumentInfo implements Durable, Parcelable { }; public static DocumentInfo fromDirectoryCursor(Cursor cursor) { + assert(cursor != null); final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY); return fromCursor(cursor, authority); } public static DocumentInfo fromCursor(Cursor cursor, String authority) { + assert(cursor != null); final DocumentInfo info = new DocumentInfo(); info.updateFromCursor(cursor, authority); return info; diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java index 0709652ec0dc..d54bdfd580eb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java @@ -334,15 +334,6 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> { } } - public Drawable loadToolbarIcon(Context context) { - if (derivedIcon != 0) { - return IconUtils.applyTintAttr(context, derivedIcon, - android.R.attr.colorControlNormal); - } else { - return IconUtils.loadPackageIcon(context, authority, icon); - } - } - @Override public boolean equals(Object o) { if (o == null) { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java index 0c0e0b7133dd..cc119fec8267 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java @@ -76,6 +76,11 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase { public void onSelectionChanged(Set<String> updatedSelection) { lastSelection = updatedSelection; } + + @Override + public boolean onBeforeItemStateChange(String id, boolean nextState) { + return true; + } }); } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java index 00d31a71a2d6..90dd4406346a 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java @@ -16,6 +16,7 @@ package com.android.mtp; +import android.annotation.Nullable; import android.content.Context; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; @@ -27,6 +28,7 @@ import android.mtp.MtpDevice; import android.mtp.MtpDeviceInfo; import android.mtp.MtpEvent; import android.mtp.MtpObjectInfo; +import android.mtp.MtpStorageInfo; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -80,9 +82,7 @@ class MtpManager { } } - if (rawDevice == null) { - throw new IOException("Not found USB device: " + deviceId); - } + ensureNotNull(rawDevice, "Not found USB device: " + deviceId); if (!mManager.hasPermission(rawDevice)) { mManager.grantPermission(rawDevice); @@ -93,10 +93,9 @@ class MtpManager { final MtpDevice device = new MtpDevice(rawDevice); - final UsbDeviceConnection connection = mManager.openDevice(rawDevice); - if (connection == null) { - throw new IOException("Failed to open a USB connection."); - } + final UsbDeviceConnection connection = ensureNotNull( + mManager.openDevice(rawDevice), + "Failed to open a USB connection."); if (!device.open(connection)) { // We cannot open connection when another application use the device. @@ -104,13 +103,11 @@ class MtpManager { } // Handle devices that fail to obtain storages just after opening a MTP session. - final int[] storageIds = device.getStorageIds(); - if (storageIds == null) { - throw new IOException("Not found MTP storages in the device."); - } + final int[] storageIds = ensureNotNull( + device.getStorageIds(), + "Not found MTP storages in the device."); mDevices.put(deviceId, device); - return createDeviceRecord(rawDevice); } @@ -133,11 +130,9 @@ class MtpManager { MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - final MtpObjectInfo info = device.getObjectInfo(objectHandle); - if (info == null) { - throw new IOException("Failed to get object info: " + objectHandle); - } - return info; + return ensureNotNull( + device.getObjectInfo(objectHandle), + "Failed to get object info: " + objectHandle); } } @@ -145,12 +140,9 @@ class MtpManager { throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - final int[] handles = - device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle); - if (handles == null) { - throw new IOException("Failed to fetch object handles."); - } - return handles; + return ensureNotNull( + device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle), + "Failed to fetch object handles."); } } @@ -158,7 +150,9 @@ class MtpManager { throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - return device.getObject(objectHandle, expectedSize); + return ensureNotNull( + device.getObject(objectHandle, expectedSize), + "Failed to fetch object bytes"); } } @@ -181,7 +175,9 @@ class MtpManager { byte[] getThumbnail(int deviceId, int objectHandle) throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - return device.getThumbnail(objectHandle); + return ensureNotNull( + device.getThumbnail(objectHandle), + "Failed to obtain thumbnail bytes"); } } @@ -216,7 +212,7 @@ class MtpManager { final MtpDevice device = getDevice(deviceId); synchronized (device) { final int result = (int) device.getParent(objectHandle); - if (result < 0) { + if (result == 0xffffffff) { throw new FileNotFoundException("Not found parent object"); } return result; @@ -227,7 +223,9 @@ class MtpManager { throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - device.importFile(objectHandle, target); + if (!device.importFile(objectHandle, target)) { + throw new IOException("Failed to import file to FD"); + } } } @@ -243,26 +241,25 @@ class MtpManager { } private synchronized MtpDevice getDevice(int deviceId) throws IOException { - final MtpDevice device = mDevices.get(deviceId); - if (device == null) { - throw new IOException("USB device " + deviceId + " is not opened."); - } - return device; + return ensureNotNull( + mDevices.get(deviceId), + "USB device " + deviceId + " is not opened."); } private MtpRoot[] getRoots(int deviceId) throws IOException { final MtpDevice device = getDevice(deviceId); synchronized (device) { - final int[] storageIds = device.getStorageIds(); - if (storageIds == null) { - throw new IOException("Failed to obtain storage IDs."); - } - final MtpRoot[] results = new MtpRoot[storageIds.length]; + final int[] storageIds = + ensureNotNull(device.getStorageIds(), "Failed to obtain storage IDs."); + final ArrayList<MtpRoot> roots = new ArrayList<>(); for (int i = 0; i < storageIds.length; i++) { - results[i] = new MtpRoot( - device.getDeviceId(), device.getStorageInfo(storageIds[i])); + final MtpStorageInfo info = device.getStorageInfo(storageIds[i]); + if (info == null) { + continue; + } + roots.add(new MtpRoot(device.getDeviceId(), info)); } - return results; + return roots.toArray(new MtpRoot[roots.size()]); } } @@ -313,4 +310,12 @@ class MtpManager { } return false; } + + private static <T> T ensureNotNull(@Nullable T t, String errorMessage) throws IOException { + if (t != null) { + return t; + } else { + throw new IOException(errorMessage); + } + } } diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 084acacf8c78..985fe3ccc1bc 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -804,7 +804,7 @@ <string name="disabled_by_admin">Disabled by administrator</string> <!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] --> - <string name="home">Home</string> + <string name="home">Settings Home</string> <string-array name="battery_labels" translatable="false"> <item>0%</item> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index d353f31e59b1..888103439a02 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -534,6 +534,7 @@ public class ApplicationsState { Comparator<AppEntry> mRebuildComparator; ArrayList<AppEntry> mRebuildResult; ArrayList<AppEntry> mLastAppList; + boolean mRebuildForeground; Session(Callbacks callbacks) { mCallbacks = callbacks; @@ -572,6 +573,11 @@ public class ApplicationsState { // Creates a new list of app entries with the given filter and comparator. public ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator) { + return rebuild(filter, comparator, true); + } + + public ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator, + boolean foreground) { synchronized (mRebuildSync) { synchronized (mEntriesMap) { mRebuildingSessions.add(this); @@ -579,6 +585,7 @@ public class ApplicationsState { mRebuildAsync = false; mRebuildFilter = filter; mRebuildComparator = comparator; + mRebuildForeground = foreground; mRebuildResult = null; if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_REBUILD_LIST)) { Message msg = mBackgroundHandler.obtainMessage( @@ -620,10 +627,12 @@ public class ApplicationsState { mRebuildRequested = false; mRebuildFilter = null; mRebuildComparator = null; + if (mRebuildForeground) { + Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); + mRebuildForeground = false; + } } - Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); - if (filter != null) { filter.init(); } @@ -640,7 +649,10 @@ public class ApplicationsState { if (filter == null || filter.filterApp(entry)) { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock"); - entry.ensureLabel(mContext); + if (comparator != null) { + // Only need the label if we are going to be sorting. + entry.ensureLabel(mContext); + } if (DEBUG) Log.i(TAG, "Using " + entry.info.packageName + ": " + entry); filteredApps.add(entry); if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock"); @@ -648,7 +660,9 @@ public class ApplicationsState { } } - Collections.sort(filteredApps, comparator); + if (comparator != null) { + Collections.sort(filteredApps, comparator); + } synchronized (mRebuildSync) { if (!mRebuildRequested) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index ff7019024165..bcbc6ac28f0a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -216,6 +216,8 @@ public class SettingsDrawerActivity extends Activity { if (sDashboardCategories == null) { sTileCache = new HashMap<>(); sConfigTracker = new InterestingConfigChanges(); + // Apply initial current config. + sConfigTracker.applyNewConfig(getResources()); sDashboardCategories = TileUtils.getCategories(this, sTileCache); } return sDashboardCategories; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 640399f0e891..8dc247a010a2 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1324,6 +1324,9 @@ public class SettingsProvider extends ContentProvider { } private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) { + if (setting == null) { + return; + } final int columnCount = cursor.getColumnCount(); String[] values = new String[columnCount]; diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml index 5d901896cc4a..bee15dd5e5c7 100644 --- a/packages/Shell/res/values/strings.xml +++ b/packages/Shell/res/values/strings.xml @@ -20,8 +20,6 @@ <string name="bugreport_in_progress_title">Bug report <xliff:g id="id">#%d</xliff:g> is being generated</string> <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] --> <string name="bugreport_finished_title">Bug report <xliff:g id="id">#%d</xliff:g> captured</string> - <!-- Title of notification indicating a bugreport has been successfully captured, but screenshot is not finished yet. [CHAR LIMIT=50] --> - <string name="bugreport_finished_pending_screenshot_title">Bug report <xliff:g id="id">#%d</xliff:g> captured but screenshot pending</string> <!-- Title of notification indicating a bugreport is being updated before it can be shared. [CHAR LIMIT=50] --> <string name="bugreport_updating_title">Adding details to the bug report</string> <!-- Content notification indicating a bugreport is being updated before it can be shared, asking the user to wait [CHAR LIMIT=50] --> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 7ca76141a84c..f0ddcb914dcf 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -220,6 +220,7 @@ public class BugreportProgressService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + Log.v(TAG, "onStartCommand(): " + dumpIntent(intent)); if (intent != null) { // Handle it in a separate thread. final Message msg = mMainHandler.obtainMessage(); @@ -297,6 +298,7 @@ public class BugreportProgressService extends Service { return; } final Parcelable parcel = ((Intent) msg.obj).getParcelableExtra(EXTRA_ORIGINAL_INTENT); + Log.v(TAG, "handleMessage(): " + dumpIntent((Intent) parcel)); final Intent intent; if (parcel instanceof Intent) { // The real intent was passed to BugreportReceiver, which delegated to the service. @@ -707,7 +709,8 @@ public class BugreportProgressService extends Service { for (int i = 0; i < mProcesses.size(); i++) { final BugreportInfo info = mProcesses.valueAt(i); if (info.finished) { - Log.d(TAG, "Not updating progress because share notification was already sent"); + Log.d(TAG, "Not updating progress for " + info.id + " while taking screenshot" + + " because share notification was already sent"); continue; } updateProgress(info); @@ -846,7 +849,15 @@ public class BugreportProgressService extends Service { private static Intent buildSendIntent(Context context, BugreportInfo info) { // Files are kept on private storage, so turn into Uris that we can // grant temporary permissions for. - final Uri bugreportUri = getUri(context, info.bugreportFile); + final Uri bugreportUri; + try { + bugreportUri = getUri(context, info.bugreportFile); + } catch (IllegalArgumentException e) { + // Should not happen on production, but happens when a Shell is sideloaded and + // FileProvider cannot find a configured root for it. + Log.wtf(TAG, "Could not get URI for " + info.bugreportFile, e); + return null; + } final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); final String mimeType = "application/vnd.android.bugreport"; @@ -907,6 +918,12 @@ public class BugreportProgressService extends Service { addDetailsToZipFile(mContext, info); final Intent sendIntent = buildSendIntent(mContext, info); + if (sendIntent == null) { + Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built"); + stopProgress(id); + return; + } + final Intent notifIntent; // Send through warning dialog by default @@ -939,15 +956,10 @@ public class BugreportProgressService extends Service { shareIntent.putExtra(EXTRA_ID, info.id); shareIntent.putExtra(EXTRA_INFO, info); - final String title, content; - if (takingScreenshot) { - title = context.getString(R.string.bugreport_finished_pending_screenshot_title, - info.id); - content = context.getString(R.string.bugreport_finished_pending_screenshot_text); - } else { - title = context.getString(R.string.bugreport_finished_title, info.id); - content = context.getString(R.string.bugreport_finished_text); - } + final String title = context.getString(R.string.bugreport_finished_title, info.id); + final String content = takingScreenshot ? + context.getString(R.string.bugreport_finished_pending_screenshot_text) + : context.getString(R.string.bugreport_finished_text); final Notification.Builder builder = newBaseNotification(context) .setContentTitle(title) .setTicker(title) @@ -1165,6 +1177,52 @@ public class BugreportProgressService extends Service { } } + /** + * Dumps an intent, extracting the relevant extras. + */ + static String dumpIntent(Intent intent) { + if (intent == null) { + return "NO INTENT"; + } + String action = intent.getAction(); + if (action == null) { + // Happens when BugreportReceiver calls startService... + action = "no action"; + } + final StringBuilder buffer = new StringBuilder(action).append(" extras: "); + addExtra(buffer, intent, EXTRA_ID); + addExtra(buffer, intent, EXTRA_PID); + addExtra(buffer, intent, EXTRA_MAX); + addExtra(buffer, intent, EXTRA_NAME); + addExtra(buffer, intent, EXTRA_DESCRIPTION); + addExtra(buffer, intent, EXTRA_BUGREPORT); + addExtra(buffer, intent, EXTRA_SCREENSHOT); + addExtra(buffer, intent, EXTRA_INFO); + + if (intent.hasExtra(EXTRA_ORIGINAL_INTENT)) { + buffer.append(SHORT_EXTRA_ORIGINAL_INTENT).append(": "); + final Intent originalIntent = intent.getParcelableExtra(EXTRA_ORIGINAL_INTENT); + buffer.append(dumpIntent(originalIntent)); + } else { + buffer.append("no ").append(SHORT_EXTRA_ORIGINAL_INTENT); + } + + return buffer.toString(); + } + + private static final String SHORT_EXTRA_ORIGINAL_INTENT = + EXTRA_ORIGINAL_INTENT.substring(EXTRA_ORIGINAL_INTENT.lastIndexOf('.') + 1); + + private static void addExtra(StringBuilder buffer, Intent intent, String name) { + final String shortName = name.substring(name.lastIndexOf('.') + 1); + if (intent.hasExtra(name)) { + buffer.append(shortName).append('=').append(intent.getExtra(name)); + } else { + buffer.append("no ").append(shortName); + } + buffer.append(", "); + } + private static boolean setSystemProperty(String key, String value) { try { if (DEBUG) Log.v(TAG, "Setting system property " + key + " to " + value); diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java index cbd17bfa3971..f6e558f73459 100644 --- a/packages/Shell/src/com/android/shell/BugreportReceiver.java +++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java @@ -20,6 +20,7 @@ import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT; import static com.android.shell.BugreportProgressService.EXTRA_ORIGINAL_INTENT; import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED; import static com.android.shell.BugreportProgressService.getFileExtra; +import static com.android.shell.BugreportProgressService.dumpIntent; import java.io.File; @@ -51,7 +52,7 @@ public class BugreportReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - Log.d(TAG, "onReceive: " + intent); + Log.d(TAG, "onReceive(): " + dumpIntent(intent)); // Clean up older bugreports in background cleanupOldFiles(this, intent, INTENT_BUGREPORT_FINISHED, MIN_KEEP_COUNT, MIN_KEEP_AGE); diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index 3b5305527ba5..3eb7754aff41 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -131,9 +131,6 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private static final boolean RENAMED_SCREENSHOTS = true; private static final boolean DIDNT_RENAME_SCREENSHOTS = false; - private static final boolean PENDING_SCREENSHOT = true; - private static final boolean NOT_PENDING_SCREENSHOT = false; - private String mDescription; private String mPlainTextPath; @@ -432,7 +429,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { sendBugreportStarted(ID2, PID2, NAME2, 1000); sendBugreportFinished(ID, mZipPath, mScreenshotPath); - Bundle extras = acceptBugreportAndGetSharedIntent(ID, PENDING_SCREENSHOT); + Bundle extras = acceptBugreportAndGetSharedIntent(ID); detailsUi = new DetailsUi(mUiBot, ID2); detailsUi.assertName(NAME2); @@ -623,7 +620,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath, String screenshotPath) { sendBugreportFinished(id, bugreportPath, screenshotPath); - return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT); + return acceptBugreportAndGetSharedIntent(id); } /** @@ -632,11 +629,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * @return extras sent in the shared intent. */ private Bundle acceptBugreportAndGetSharedIntent(int id) { - return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT); - } - - private Bundle acceptBugreportAndGetSharedIntent(int id, boolean pendingScreenshot) { - acceptBugreport(id, pendingScreenshot); + acceptBugreport(id); mUiBot.chooseActivity(UI_NAME); return mListener.getExtras(); } @@ -652,13 +645,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * Accepts the notification to share the finished bugreport. */ private void acceptBugreport(int id) { - acceptBugreport(id, NOT_PENDING_SCREENSHOT); - } - - private void acceptBugreport(int id, boolean pendingScreenshot) { - final int res = pendingScreenshot ? R.string.bugreport_finished_pending_screenshot_title - : R.string.bugreport_finished_title; - mUiBot.clickOnNotification(mContext.getString(res, id)); + mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id)); } /** diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index f5854f5f7a36..c248adfce690 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -159,6 +159,9 @@ <!-- DND access --> <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" /> + <!-- It's like, reality, but, you know, virtual --> + <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" /> + <application android:name=".SystemUIApplication" android:persistent="true" @@ -235,6 +238,19 @@ android:value="com.android.settings.category.system" /> </activity> + <activity-alias android:name=".DemoMode" + android:targetActivity=".tuner.TunerActivity" + android:icon="@drawable/tuner" + android:theme="@style/TunerSettings" + android:label="@string/demo_mode" + android:process=":tuner" + android:exported="true"> + <intent-filter> + <action android:name="com.android.settings.action.DEMO_MODE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity-alias> + <!-- Service used by secondary users to register themselves with the system user. --> <service android:name=".recents.RecentsSystemUserService" android:exported="false" diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml index cfaf01826885..70e5451eed57 100644 --- a/packages/SystemUI/res/layout/docked_stack_divider.xml +++ b/packages/SystemUI/res/layout/docked_stack_divider.xml @@ -24,6 +24,11 @@ android:id="@+id/docked_divider_background" android:background="@color/docked_divider_background"/> + <com.android.systemui.stackdivider.MinimizedDockShadow + style="@style/DockedDividerMinimizedShadow" + android:id="@+id/minimized_dock_shadow" + android:alpha="0"/>"> + <com.android.systemui.stackdivider.DividerHandleView style="@style/DockedDividerHandle" android:id="@+id/docked_divider_handle" diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml index b711faa30280..82cba58e48fa 100644 --- a/packages/SystemUI/res/values-land/styles.xml +++ b/packages/SystemUI/res/values-land/styles.xml @@ -31,4 +31,8 @@ <item name="android:layout_height">96dp</item> </style> + <style name="DockedDividerMinimizedShadow"> + <item name="android:layout_width">8dp</item> + <item name="android:layout_height">match_parent</item> + </style> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 18fc4196daa0..d26fb061bb24 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -151,7 +151,9 @@ <color name="docked_divider_background">#ff000000</color> <color name="docked_divider_handle">#ffffff</color> - <drawable name="forced_resizable_background">#40000000</drawable> + <drawable name="forced_resizable_background">#59000000</drawable> + <color name="minimize_dock_shadow_start">#60000000</color> + <color name="minimize_dock_shadow_end">#00000000</color> <color name="default_remote_input_background">@*android:color/notification_default_color</color> <color name="remote_input_hint">#99ffffff</color> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index f560a138ba22..0730083b6592 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -308,6 +308,11 @@ <item name="android:layout_gravity">center_vertical</item> </style> + <style name="DockedDividerMinimizedShadow"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">8dp</item> + </style> + <style name="DockedDividerHandle"> <item name="android:layout_gravity">center_horizontal</item> <item name="android:layout_width">96dp</item> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java index 087f61eda211..076b5bcd0861 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -37,7 +37,7 @@ import android.provider.Settings; import com.android.systemui.statusbar.policy.BatteryController; -public class BatteryMeterDrawable extends Drawable implements DemoMode, +public class BatteryMeterDrawable extends Drawable implements BatteryController.BatteryStateChangeCallback { private static final float ASPECT_RATIO = 9.5f / 14.5f; @@ -184,14 +184,12 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); updateShowPercent(); - if (mDemoMode) return; mBatteryController.addStateChangedCallback(this); } public void stopListening() { mListening = false; mContext.getContentResolver().unregisterContentObserver(mSettingObserver); - if (mDemoMode) return; mBatteryController.removeStateChangedCallback(this); } @@ -507,35 +505,6 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, return 0; } - private boolean mDemoMode; - - @Override - public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mBatteryController.removeStateChangedCallback(this); - mDemoMode = true; - if (mListening) { - mBatteryController.removeStateChangedCallback(this); - } - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - postInvalidate(); - if (mListening) { - mBatteryController.addStateChangedCallback(this); - } - } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { - String level = args.getString("level"); - String plugged = args.getString("plugged"); - if (level != null) { - mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); - } - if (plugged != null) { - mPluggedIn = Boolean.parseBoolean(plugged); - } - postInvalidate(); - } - } - private final class SettingObserver extends ContentObserver { public SettingObserver() { super(new Handler()); diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index 001d1f23af62..73b9d02e403a 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -32,7 +32,8 @@ public interface RecentsComponent { /** * Docks the top-most task and opens recents. */ - boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds); + boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds, + int metricsDockAction); /** * Called during a drag-from-navbar-in gesture. diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 455a69fcc77b..39a341216f2c 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -63,7 +63,8 @@ public class SystemUIApplication extends Application { * above. */ private final Class<?>[] SERVICES_PER_USER = new Class[] { - com.android.systemui.recents.Recents.class + com.android.systemui.recents.Recents.class, + com.android.systemui.tv.pip.PipUI.class }; /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 4d959d8cdadb..af81c196e4f3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -87,6 +87,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha public void setOnKeyguard(boolean onKeyguard) { mOnKeyguard = onKeyguard; + mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE); if (mOnKeyguard) { clearAnimationState(); } @@ -290,7 +291,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha @Override public void onAnimationStarted() { - mQuickQsPanel.setVisibility(View.VISIBLE); + mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE); if (mOnFirstPage) { final int N = mTopFiveQs.size(); for (int i = 0; i < N; i++) { @@ -302,12 +303,11 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private void clearAnimationState() { final int N = mAllViews.size(); mQuickQsPanel.setAlpha(0); - mQuickQsPanel.setVisibility(View.VISIBLE); for (int i = 0; i < N; i++) { View v = mAllViews.get(i); v.setAlpha(1); - v.setTranslationX(1); - v.setTranslationY(1); + v.setTranslationX(0); + v.setTranslationY(0); } final int N2 = mTopFiveQs.size(); for (int i = 0; i < N2; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java index e3a4909a7dcb..ef7556267e0c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java @@ -70,8 +70,8 @@ public class QSContainer extends FrameLayout { super.onFinishInflate(); mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel); mQSDetail = (QSDetail) findViewById(R.id.qs_detail); - mQSDetail.setQsPanel(mQSPanel); mHeader = (BaseStatusBarHeader) findViewById(R.id.header); + mQSDetail.setQsPanel(mQSPanel, mHeader); mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 50c0cca8d8e7..0cf7e4793941 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -35,6 +35,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.qs.QSTile.DetailAdapter; +import com.android.systemui.statusbar.phone.BaseStatusBarHeader; import com.android.systemui.statusbar.phone.QSTileHost; public class QSDetail extends LinearLayout { @@ -62,6 +63,7 @@ public class QSDetail extends LinearLayout { private boolean mClosingDetail; private boolean mFullyExpanded; private View mQsDetailHeaderBack; + private BaseStatusBarHeader mHeader; public QSDetail(Context context, @Nullable AttributeSet attrs) { super(context, attrs); @@ -107,8 +109,9 @@ public class QSDetail extends LinearLayout { mDetailDoneButton.setOnClickListener(doneListener); } - public void setQsPanel(QSPanel panel) { + public void setQsPanel(QSPanel panel, BaseStatusBarHeader header) { mQsPanel = panel; + mHeader = header; mQsPanel.setCallback(mQsPanelCallback); } @@ -195,6 +198,7 @@ public class QSDetail extends LinearLayout { mClosingDetail = true; mDetailAdapter = null; listener = mTeardownDetailWhenDone; + mHeader.setVisibility(View.VISIBLE); mQsPanel.setGridContentVisibility(true); mQsPanelCallback.onScanStateChanged(false); } @@ -273,6 +277,7 @@ public class QSDetail extends LinearLayout { // Only hide content if still in detail state. if (mDetailAdapter != null) { mQsPanel.setGridContentVisibility(false); + mHeader.setVisibility(View.INVISIBLE); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 82daaa608fa2..b2d7b4866fae 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -23,6 +23,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; @@ -36,10 +37,13 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.EventLog; import android.util.Log; +import android.util.MutableBoolean; import android.view.Display; import android.view.View; import android.widget.Toast; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -78,6 +82,10 @@ public class Recents extends SystemUI private final static String ACTION_HIDE_RECENTS = "com.android.systemui.recents.ACTION_HIDE"; private final static String ACTION_TOGGLE_RECENTS = "com.android.systemui.recents.ACTION_TOGGLE"; + private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported"; + private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported"; + private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible"; + private static SystemServicesProxy sSystemServicesProxy; private static RecentsDebugFlags sDebugFlags; private static RecentsTaskLoader sTaskLoader; @@ -393,7 +401,8 @@ public class Recents extends SystemUI } @Override - public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds) { + public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds, + int metricsDockAction) { // Ensure the device has been provisioned before allowing the user to interact with // recents if (!isUserSetup()) { @@ -413,7 +422,12 @@ public class Recents extends SystemUI boolean screenPinningActive = ssp.isScreenPinningActive(); boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId); if (topTask != null && !isTopTaskHome && !screenPinningActive) { + logDockAttempt(mContext, topTask.topActivity, topTask.resizeMode); if (topTask.isDockable) { + if (metricsDockAction != -1) { + MetricsLogger.action(mContext, metricsDockAction, + topTask.topActivity.flattenToShortString()); + } if (sSystemServicesProxy.isSystemUser(currentUser)) { mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds); } else { @@ -444,6 +458,26 @@ public class Recents extends SystemUI } } + public static void logDockAttempt(Context ctx, ComponentName activity, int resizeMode) { + if (resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE) { + MetricsLogger.action(ctx, MetricsEvent.ACTION_WINDOW_DOCK_UNRESIZABLE, + activity.flattenToShortString()); + } + MetricsLogger.count(ctx, getMetricsCounterForResizeMode(resizeMode), 1); + } + + private static String getMetricsCounterForResizeMode(int resizeMode) { + switch (resizeMode) { + case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE: + return COUNTER_WINDOW_UNSUPPORTED; + case ActivityInfo.RESIZE_MODE_RESIZEABLE: + case ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE: + return COUNTER_WINDOW_SUPPORTED; + default: + return COUNTER_WINDOW_INCOMPATIBLE; + } + } + @Override public void onDraggingInRecents(float distanceFromTop) { if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 44f220bb76a0..4ecda542ca36 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -25,6 +25,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; +import android.os.Trace; import android.util.ArraySet; import android.util.IntProperty; import android.util.Property; @@ -261,6 +262,14 @@ public class Utilities { } /** + * Adds a trace event for debugging. + */ + public static void addTraceEvent(String event) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, event); + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + + /** * Returns a lightweight dump of a rect. */ public static String dumpRect(Rect r) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 7aeff1feca71..af1628b417a5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -206,7 +206,7 @@ public class RecentsTaskLoadPlan { Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon, thumbnail, title, titleDescription, dismissDescription, appInfoDescription, activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp, - t.isDockable, t.bounds, t.taskDescription); + t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity); allTasks.add(task); affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 24eeaf27f032..9f9c48fcff3b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -19,6 +19,7 @@ package com.android.systemui.recents.model; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; @@ -174,6 +175,15 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public boolean isDockable; + /** + * Resize mode. See {@link ActivityInfo#resizeMode}. + */ + @ViewDebug.ExportedProperty(category="recents") + public int resizeMode; + + @ViewDebug.ExportedProperty(category="recents") + public ComponentName topActivity; + private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>(); public Task() { @@ -184,7 +194,8 @@ public class Task { Bitmap thumbnail, String title, String titleDescription, String dismissDescription, String appInfoDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp, - boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) { + boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription, + int resizeMode, ComponentName topActivity) { boolean isInAffiliationGroup = (affiliationTaskId != key.id); boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0); this.key = key; @@ -206,6 +217,8 @@ public class Task { this.isStackTask = isStackTask; this.isSystemApp = isSystemApp; this.isDockable = isDockable; + this.resizeMode = resizeMode; + this.topActivity = topActivity; } /** @@ -231,6 +244,8 @@ public class Task { this.isStackTask = o.isStackTask; this.isSystemApp = o.isSystemApp; this.isDockable = o.isDockable; + this.resizeMode = o.resizeMode; + this.topActivity = o.topActivity; } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java index 13e1a14ead63..60a85df5605f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java @@ -55,6 +55,7 @@ import com.android.systemui.recents.tv.animations.HomeRecentsEnterExitAnimationH import com.android.systemui.recents.tv.views.RecentsTvView; import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView; import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter; +import com.android.systemui.recents.views.AnimationProps; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.tv.pip.PipManager; import com.android.systemui.tv.pip.PipRecentsOverlayManager; @@ -246,7 +247,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable); dismissEvent.addPostAnimationCallback(closeSystemWindows); - if(mTaskStackHorizontalGridView.getChildCount() > 0) { + if(mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) { mHomeRecentsEnterExitAnimationHolder.startExitAnimation(dismissEvent); } else { closeSystemWindows.run(); @@ -343,6 +344,13 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { } else { mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); } + if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) { + // If there are 2 or more tasks, and we are not launching from home + // set the selected position to the 2nd task to allow for faster app switching + mTaskStackHorizontalGridView.setSelectedPosition(1); + } else { + mTaskStackHorizontalGridView.setSelectedPosition(0); + } // If this is a new instance from a configuration change, then we have to manually trigger // the enter animation state, or if recents was relaunched by AM, without going through @@ -494,12 +502,10 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { } public final void onBusEvent(AllTaskViewsDismissedEvent event) { - SystemServicesProxy ssp = Recents.getSystemServices(); - if (ssp.hasDockedTask()) { + if (mPipManager.isPipShown()) { mRecentsView.showEmptyView(); } else { - // Just go straight home (no animation necessary because there are no more task views) - dismissRecentsToHome(false /* animateTaskViews */); + dismissRecentsToHome(false); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java index fd3187205565..dc0d1f1fe465 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java @@ -75,7 +75,8 @@ public class RecentsTvImpl extends RecentsImpl{ if (useThumbnailTransition) { // Try starting with a thumbnail transition - ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask); + ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask, + stack.getTaskCount()); if (opts != null) { startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */); } else { @@ -118,8 +119,8 @@ public class RecentsTvImpl extends RecentsImpl{ * Creates the activity options for an app->recents transition on TV. */ private ActivityOptions getThumbnailTransitionActivityOptionsForTV( - ActivityManager.RunningTaskInfo topTask) { - Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext); + ActivityManager.RunningTaskInfo topTask, int numTasks) { + Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext, numTasks); SystemServicesProxy ssp = Recents.getSystemServices(); ThumbnailData thumbnailData = ssp.getTaskThumbnail(topTask.id); if (thumbnailData.thumbnail != null) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java index fbcfa9779682..3e668afbb47e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java @@ -26,13 +26,13 @@ import com.android.systemui.R; public class DismissAnimationsHolder { private LinearLayout mDismissArea; - private LinearLayout mTaskCardView; + private LinearLayout mRecentsTvCard; private int mCardYDelta; private long mShortDuration; private long mLongDuration; public DismissAnimationsHolder(TaskCardView taskCardView) { - mTaskCardView = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card); + mRecentsTvCard = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card); mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss); Resources res = taskCardView.getResources(); @@ -47,7 +47,7 @@ public class DismissAnimationsHolder { .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(1.0f); - mTaskCardView.animate() + mRecentsTvCard.animate() .setDuration(mShortDuration) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .translationYBy(mCardYDelta) @@ -60,7 +60,7 @@ public class DismissAnimationsHolder { .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(0.0f); - mTaskCardView.animate() + mRecentsTvCard.animate() .setDuration(mShortDuration) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .translationYBy(-mCardYDelta) @@ -73,11 +73,17 @@ public class DismissAnimationsHolder { .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(0.0f); - mTaskCardView.animate() + mRecentsTvCard.animate() .setDuration(mLongDuration) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .translationYBy(mCardYDelta) .alpha(0.0f) .setListener(listener); } + + public void reset() { + mRecentsTvCard.setAlpha(1.0f); + mRecentsTvCard.setTranslationY(0); + mRecentsTvCard.animate().setListener(null); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java index 53fdf62c6620..b876fc701372 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java @@ -250,8 +250,9 @@ public class RecentsTvView extends FrameLayout { public TaskStackHorizontalGridView setTaskStackViewAdapter( TaskStackHorizontalViewAdapter taskStackViewAdapter) { - if(mTaskStackHorizontalView != null) { + if (mTaskStackHorizontalView != null) { mTaskStackHorizontalView.setAdapter(taskStackViewAdapter); + taskStackViewAdapter.setTaskStackHorizontalGridView(mTaskStackHorizontalView); } return mTaskStackHorizontalView; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java index 99d478b2e8d1..d3bc4b6ea888 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java @@ -95,7 +95,38 @@ public class TaskCardView extends LinearLayout { return r; } - public static Rect getStartingCardThumbnailRect(Context context) { + public static Rect getStartingCardThumbnailRect(Context context, int numberOfTasks) { + if(numberOfTasks > 1) { + return getStartingCardThumbnailRectForStartPosition(context); + } else { + return getStartingCardThumbnailRectForFocusedPosition(context); + } + } + + private static Rect getStartingCardThumbnailRectForStartPosition(Context context) { + Resources res = context.getResources(); + + int width = res.getDimensionPixelOffset(R.dimen.recents_tv_card_width); + int totalSpacing = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_card_spacing) * 2 + + res.getDimensionPixelOffset(R.dimen.recents_tv_gird_focused_card_delta); + int height = res.getDimensionPixelOffset(R.dimen.recents_tv_screenshot_height); + int topMargin = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_row_top_margin); + int headerHeight = res.getDimensionPixelOffset(R.dimen.recents_tv_card_extra_badge_size) + + res.getDimensionPixelOffset(R.dimen.recents_tv_icon_padding_bottom); + + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + int screenWidth = size.x; + + return new Rect(screenWidth / 2 + width / 2 + totalSpacing, + topMargin + headerHeight, + screenWidth / 2 + width / 2 + totalSpacing + width, + topMargin + headerHeight + height); + } + + private static Rect getStartingCardThumbnailRectForFocusedPosition(Context context) { Resources res = context.getResources(); TypedValue out = new TypedValue(); @@ -127,7 +158,6 @@ public class TaskCardView extends LinearLayout { Point size = new Point(); display.getSize(size); int screenWidth = size.x; - int screenHeight = size.y; return new Rect(screenWidth / 2 - width / 2 - widthDelta / 2, topMargin - totalHeightDelta / 2 + (int) (headerHeight * scale), @@ -189,6 +219,7 @@ public class TaskCardView extends LinearLayout { } public void startDismissTaskAnimation(Animator.AnimatorListener listener) { + mDismissState = false; mDismissAnimationsHolder.startDismissAnimation(listener); } @@ -201,4 +232,10 @@ public class TaskCardView extends LinearLayout { super.onDetachedFromWindow(); setDismissState(false); } + + public void reset() { + mDismissState = false; + mRecentsRowFocusAnimationHolder.reset(); + mDismissAnimationsHolder.reset(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java index 603721a56eca..77ab8c1c1f8c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java @@ -179,13 +179,14 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T @Override public void onStackTaskAdded(TaskStack stack, Task newTask) { - getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask)); + ((TaskStackHorizontalViewAdapter) getAdapter()).addTaskAt(newTask, + stack.indexOfStackTask(newTask)); } @Override public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask, Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) { - getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask)); + ((TaskStackHorizontalViewAdapter) getAdapter()).removeTask(removedTask); if (mFocusedTask == removedTask) { resetFocusedTask(removedTask); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java index 97712ea9ce86..eff184507740 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java @@ -27,7 +27,9 @@ import com.android.systemui.R; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.LaunchTvTaskEvent; import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; +import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.views.AnimationProps; import java.util.ArrayList; import java.util.List; @@ -40,6 +42,7 @@ public class TaskStackHorizontalViewAdapter extends //Full class name is 30 characters private static final String TAG = "TaskStackViewAdapter"; private List<Task> mTaskList; + private TaskStackHorizontalGridView mGridView; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private TaskCardView mTaskCardView; @@ -62,7 +65,7 @@ public class TaskStackHorizontalViewAdapter extends try { if (mTaskCardView.isInDismissState()) { mTaskCardView.startDismissTaskAnimation( - getRemoveAtListener(getAdapterPosition(), mTaskCardView)); + getRemoveAtListener(getAdapterPosition(), mTaskCardView.getTask())); } else { EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask, null, INVALID_STACK_ID)); @@ -74,6 +77,28 @@ public class TaskStackHorizontalViewAdapter extends } } + + private Animator.AnimatorListener getRemoveAtListener(final int position, + final Task task) { + return new Animator.AnimatorListener() { + + @Override + public void onAnimationStart(Animator animation) { } + + @Override + public void onAnimationEnd(Animator animation) { + removeAt(position); + EventBus.getDefault().send(new DeleteTaskDataEvent(task)); + } + + @Override + public void onAnimationCancel(Animator animation) { } + + @Override + public void onAnimationRepeat(Animator animation) { } + }; + + } } public TaskStackHorizontalViewAdapter(List tasks) { @@ -101,39 +126,43 @@ public class TaskStackHorizontalViewAdapter extends } @Override - public int getItemCount() { - return mTaskList.size(); + public void onViewDetachedFromWindow(ViewHolder holder) { + holder.mTaskCardView.reset(); } - private Animator.AnimatorListener getRemoveAtListener(final int position, - final TaskCardView taskCardView) { - return new Animator.AnimatorListener() { - - @Override - public void onAnimationStart(Animator animation) { } - - @Override - public void onAnimationEnd(Animator animation) { - removeAt(position); - EventBus.getDefault().send(new DeleteTaskDataEvent(taskCardView.getTask())); - } - - @Override - public void onAnimationCancel(Animator animation) { } - - @Override - public void onAnimationRepeat(Animator animation) { } - }; - + @Override + public int getItemCount() { + return mTaskList.size(); } private void removeAt(int position) { - mTaskList.remove(position); + Task removedTask = mTaskList.remove(position); + if (mGridView != null) { + mGridView.getStack().removeTask(removedTask, AnimationProps.IMMEDIATE, + false); + } notifyItemRemoved(position); } + public void removeTask(Task task) { + int position = mTaskList.indexOf(task); + if (position >= 0) { + mTaskList.remove(position); + notifyItemRemoved(position); + } + } + public int getPositionOfTask(Task task) { int position = mTaskList.indexOf(task); return (position >= 0) ? position : 0; } + + public void setTaskStackHorizontalGridView(TaskStackHorizontalGridView gridView) { + mGridView = gridView; + } + + public void addTaskAt(Task task, int position) { + mTaskList.add(position, task); + notifyItemInserted(position); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 21a43d5c3e52..59b7560255c5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -540,7 +540,8 @@ public class RecentsView extends FrameLayout { mTransitionHelper.wrapStartedListener(startedListener), true /* scaleUp */); - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP); + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, + event.task.topActivity.flattenToShortString()); } else { // Animate the overlay alpha back to 0 updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java index 22acb889a941..5fbc0374c789 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -41,7 +41,6 @@ import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; - /** * Represents the dock regions for each orientation. */ @@ -163,6 +162,7 @@ public class RecentsViewTouchHandler { mVisibleDockStates.clear(); if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask() && mDividerSnapAlgorithm.isSplitScreenFeasible()) { + Recents.logDockAttempt(mRv.getContext(), event.task.topActivity, event.task.resizeMode); if (!event.task.isDockable) { EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent()); } else { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index b75a91e8c42b..e4da8b369914 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -23,13 +23,13 @@ import android.content.res.Resources; import android.graphics.Path; import android.graphics.Rect; import android.util.ArraySet; +import android.util.MutableFloat; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.ViewDebug; import com.android.systemui.R; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsDebugFlags; @@ -628,22 +628,24 @@ public class TaskStackLayoutAlgorithm { /** * Updates this stack when a scroll happens. + * */ - public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) { - if (deltaScroll == 0f) { - return; + public float updateFocusStateOnScroll(float lastTargetStackScroll, float targetStackScroll, + float lastStackScroll) { + if (targetStackScroll == lastStackScroll) { + return targetStackScroll; } + float deltaScroll = targetStackScroll - lastStackScroll; + float deltaTargetScroll = targetStackScroll - lastTargetStackScroll; + float newScroll = targetStackScroll; + mUnfocusedRange.offset(targetStackScroll); for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) { int taskId = mTaskIndexOverrideMap.keyAt(i); float x = mTaskIndexMap.get(taskId); float overrideX = mTaskIndexOverrideMap.get(taskId, 0f); float newOverrideX = overrideX + deltaScroll; - mUnfocusedRange.offset(stackScroll); - boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f || - mUnfocusedRange.getNormalizedX(newOverrideX) > 1f; - if (outOfBounds || (overrideX >= x && x >= newOverrideX) || - (overrideX <= x && x <= newOverrideX)) { + if (isInvalidOverrideX(x, overrideX, newOverrideX)) { // Remove the override once we reach the original task index mTaskIndexOverrideMap.removeAt(i); } else if ((overrideX >= x && deltaScroll <= 0f) || @@ -652,11 +654,23 @@ public class TaskStackLayoutAlgorithm { mTaskIndexOverrideMap.put(taskId, newOverrideX); } else { // Scrolling override x away from x, we should still move the scroll towards x - float deltaX = overrideX - x; - newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - Math.abs(deltaScroll)); - mTaskIndexOverrideMap.put(taskId, x + newOverrideX); + newScroll = lastStackScroll; + newOverrideX = overrideX - deltaTargetScroll; + if (isInvalidOverrideX(x, overrideX, newOverrideX)) { + mTaskIndexOverrideMap.removeAt(i); + } else{ + mTaskIndexOverrideMap.put(taskId, newOverrideX); + } } } + return newScroll; + } + + private boolean isInvalidOverrideX(float x, float overrideX, float newOverrideX) { + boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f || + mUnfocusedRange.getNormalizedX(newOverrideX) > 1f; + return outOfBounds || (overrideX >= x && x >= newOverrideX) || + (overrideX <= x && x <= newOverrideX); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 13c8403ab0ab..0fc45ed8951c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -1618,7 +1618,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (animation != null) { relayoutTaskViewsOnNextFrame(animation); } - mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll); if (mEnterAnimationComplete) { if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD && diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index 19b3c943ae65..1fa73c6ef61c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.util.FloatProperty; import android.util.Log; +import android.util.MutableFloat; import android.util.Property; import android.view.ViewDebug; import android.widget.OverScroller; @@ -66,6 +67,8 @@ public class TaskStackViewScroller { @ViewDebug.ExportedProperty(category="recents") float mStackScrollP; + @ViewDebug.ExportedProperty(category="recents") + float mLastDeltaP = 0f; float mFlingDownScrollP; int mFlingDownY; @@ -84,6 +87,11 @@ public class TaskStackViewScroller { /** Resets the task scroller. */ void reset() { mStackScrollP = 0f; + mLastDeltaP = 0f; + } + + void resetDeltaScroll() { + mLastDeltaP = 0f; } /** Gets the current stack scroll */ @@ -99,14 +107,27 @@ public class TaskStackViewScroller { } /** + * Sets the current stack scroll immediately, and returns the difference between the target + * scroll and the actual scroll after accounting for the effect on the focus state. + */ + public float setDeltaStackScroll(float downP, float deltaP) { + float targetScroll = downP + deltaP; + float newScroll = mLayoutAlgorithm.updateFocusStateOnScroll(downP + mLastDeltaP, targetScroll, + mStackScrollP); + setStackScroll(newScroll, AnimationProps.IMMEDIATE); + mLastDeltaP = deltaP; + return newScroll - targetScroll; + } + + /** * Sets the current stack scroll, but indicates to the callback the preferred animation to * update to this new scroll. */ - public void setStackScroll(float s, AnimationProps animation) { - float prevStackScroll = mStackScrollP; - mStackScrollP = s; + public void setStackScroll(float newScroll, AnimationProps animation) { + float prevScroll = mStackScrollP; + mStackScrollP = newScroll; if (mCb != null) { - mCb.onStackScrollChanged(prevStackScroll, mStackScrollP, animation); + mCb.onStackScrollChanged(prevScroll, mStackScrollP, animation); } } @@ -115,9 +136,9 @@ public class TaskStackViewScroller { * @return whether the stack progress changed. */ public boolean setStackScrollToInitialState() { - float prevStackScrollP = mStackScrollP; + float prevScroll = mStackScrollP; setStackScroll(mLayoutAlgorithm.mInitialScrollP); - return Float.compare(prevStackScrollP, mStackScrollP) != 0; + return Float.compare(prevScroll, mStackScrollP) != 0; } /** @@ -227,10 +248,9 @@ public class TaskStackViewScroller { boolean computeScroll() { if (mScroller.computeScrollOffset()) { float deltaP = mLayoutAlgorithm.getDeltaPForY(mFlingDownY, mScroller.getCurrY()); - float scroll = mFlingDownScrollP + deltaP; - setStackScroll(scroll); + mFlingDownScrollP += setDeltaStackScroll(mFlingDownScrollP, deltaP); if (DEBUG) { - Log.d(TAG, "computeScroll: " + scroll); + Log.d(TAG, "computeScroll: " + (mFlingDownScrollP + deltaP)); } return true; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index ee0de1ad05df..3cdb1fb27854 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -200,6 +200,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Stop the current scroll if it is still flinging mScroller.stopScroller(); mScroller.stopBoundScrollAnimation(); + mScroller.resetDeltaScroll(); Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator); // Finish any existing task animations from the delete @@ -223,6 +224,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { mDownY = (int) ev.getY(index); mLastY = mDownY; mDownScrollP = mScroller.getStackScroll(); + mScroller.resetDeltaScroll(); mVelocityTracker.addMovement(ev); break; } @@ -256,20 +258,21 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // If we just move linearly on the screen, then that would map to 1/arclength // of the curve, so just move the scroll proportional to that float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y); - float curScrollP = mDownScrollP + deltaP; // Modulate the overscroll to prevent users from pulling the stack too far float minScrollP = layoutAlgorithm.mMinScrollP; float maxScrollP = layoutAlgorithm.mMaxScrollP; + float curScrollP = mDownScrollP + deltaP; if (curScrollP < minScrollP || curScrollP > maxScrollP) { float clampedScrollP = Utilities.clamp(curScrollP, minScrollP, maxScrollP); float overscrollP = (curScrollP - clampedScrollP); float overscrollX = Math.abs(overscrollP) / MAX_OVERSCROLL; - curScrollP = clampedScrollP + (Math.signum(overscrollP) * - (OVERSCROLL_INTERP.getInterpolation(overscrollX) * MAX_OVERSCROLL)); + float interpX = OVERSCROLL_INTERP.getInterpolation(overscrollX); + curScrollP = clampedScrollP + Math.signum(overscrollP) * + (interpX * MAX_OVERSCROLL); } - - mScroller.setStackScroll(curScrollP); + mDownScrollP += mScroller.setDeltaStackScroll(mDownScrollP, + curScrollP - mDownScrollP); mStackViewScrolledEvent.updateY(y - mLastY); EventBus.getDefault().send(mStackViewScrolledEvent); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index e5ac0d31ca8f..62fd5858bf9a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -143,43 +143,28 @@ public class TaskViewThumbnail extends View { int viewWidth = mTaskViewRect.width(); int viewHeight = mTaskViewRect.height(); - if (mBitmapShader != null) { - - // We are drawing the thumbnail in the same orientation, so just fit the width - int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale); - int thumbnailHeight = (int) (mThumbnailRect.height() * mThumbnailScale); - - if (thumbnailWidth >= viewWidth && thumbnailHeight >= viewHeight) { - // Thumbnail fills the full task view bounds, so just draw it - canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius, - mDrawPaint); - } else { - // Thumbnail does not fill the full task view bounds, so just draw it and fill the - // empty areas with the background color - int count = canvas.save(); - - // Since we only want the top corners to be rounded, draw slightly beyond the - // thumbnail height, but clip to the thumbnail height - canvas.clipRect(0, 0, thumbnailWidth, thumbnailHeight, Region.Op.REPLACE); - canvas.drawRoundRect(0, 0, - thumbnailWidth + (thumbnailWidth < viewWidth ? mCornerRadius : 0), - thumbnailHeight + (thumbnailHeight < viewHeight ? mCornerRadius : 0), - mCornerRadius, mCornerRadius, mDrawPaint); - - // In the remaining space, draw the background color - if (thumbnailWidth < viewWidth) { - canvas.clipRect(thumbnailWidth, 0, viewWidth, viewHeight, Region.Op.REPLACE); - canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0, - viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint); - } - if (thumbnailWidth > 0 && thumbnailHeight < viewHeight) { - canvas.clipRect(0, thumbnailHeight, viewWidth, viewHeight, Region.Op.REPLACE); - canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius), - viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint); - } - - canvas.restoreToCount(count); + int thumbnailWidth = Math.min(viewWidth, + (int) (mThumbnailRect.width() * mThumbnailScale)); + int thumbnailHeight = Math.min(viewHeight, + (int) (mThumbnailRect.height() * mThumbnailScale)); + if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { + // Draw the background, there will be some small overdraw with the thumbnail + if (thumbnailWidth < viewWidth) { + // Portrait thumbnail on a landscape task view + canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0, + viewWidth, viewHeight, + mCornerRadius, mCornerRadius, mBgFillPaint); } + if (thumbnailHeight < viewHeight) { + // Landscape thumbnail on a portrait task view + canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius), + viewWidth, viewHeight, + mCornerRadius, mCornerRadius, mBgFillPaint); + } + + // Draw the thumbnail + canvas.drawRoundRect(0, 0, thumbnailWidth, thumbnailHeight, + mCornerRadius, mCornerRadius, mDrawPaint); } else { canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint); diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 69dcabea28b8..0aeb7b423ca4 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -102,8 +102,8 @@ public class ShortcutKeyDispatcher extends SystemUI int dockMode = (shortcutCode == SC_DOCK_LEFT) ? ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT : ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; - recents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, dockMode, null); - MetricsLogger.action(mContext, MetricsEvent.WINDOW_DOCK_SHORTCUTS); + recents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, dockMode, null, + MetricsEvent.WINDOW_DOCK_SHORTCUTS); } else { // If there is already a docked window, we respond by resizing the docking pane. DividerView dividerView = getComponent(Divider.class).getView(); @@ -115,7 +115,8 @@ public class ShortcutKeyDispatcher extends SystemUI DividerSnapAlgorithm.SnapTarget target = snapAlgorithm.cycleNonDismissTarget( currentTarget, increment); dividerView.startDragging(true /* animate */, false /* touching */); - dividerView.stopDragging(target.position, 0f, true /* avoidDismissStart */); + dividerView.stopDragging(target.position, 0f, true /* avoidDismissStart */, + true /* logMetrics */); } } catch (RemoteException e) { Log.e(TAG, "handleDockKey() failed."); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index d294c80bdf51..2bf0b4012cd7 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -146,5 +146,10 @@ public class Divider extends SystemUI { throws RemoteException { updateMinimizedDockedStack(minimized, animDuration); } + + @Override + public void onDockSideChanged(final int newDockSide) throws RemoteException { + mView.post(() -> mView.notifyDockSideChanged(newDockSide)); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 98e0dd96ee75..a6c75e834fdf 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -54,11 +54,14 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.widget.FrameLayout; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.recents.Constants.Metrics; import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DockedTopTaskEvent; @@ -80,7 +83,13 @@ public class DividerView extends FrameLayout implements OnTouchListener, static final long TOUCH_ANIMATION_DURATION = 150; static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; - private static final String TAG = "DividerView"; + private static final int LOG_VALUE_RESIZE_50_50 = 0; + private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1; + private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2; + + private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0; + private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1; + private static final int TASK_POSITION_SAME = Integer.MAX_VALUE; private static final boolean SWAPPING_ENABLED = false; @@ -88,7 +97,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, /** * How much the background gets scaled when we are in the minimized dock state. */ - private static final float MINIMIZE_DOCK_SCALE = 0.375f; + private static final float MINIMIZE_DOCK_SCALE = 0f; private static final PathInterpolator SLOWDOWN_INTERPOLATOR = new PathInterpolator(0.5f, 1f, 0.5f, 1f); @@ -97,6 +106,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private DividerHandleView mHandle; private View mBackground; + private MinimizedDockShadow mMinimizedShadow; private int mStartX; private int mStartY; private int mStartPosition; @@ -133,6 +143,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mGrowRecents; private ValueAnimator mCurrentAnimator; private boolean mEntranceAnimationRunning; + private boolean mExitAnimationRunning; + private int mExitStartPosition; private GestureDetector mGestureDetector; private boolean mDockedStackMinimized; @@ -201,6 +213,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, super.onFinishInflate(); mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle); mBackground = findViewById(R.id.docked_divider_background); + mMinimizedShadow = (MinimizedDockShadow) findViewById(R.id.minimized_dock_shadow); mHandle.setOnTouchListener(this); mDividerWindowWidth = getResources().getDimensionPixelSize( com.android.internal.R.dimen.docked_stack_divider_thickness); @@ -267,6 +280,18 @@ public class DividerView extends FrameLayout implements OnTouchListener, @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + int minimizeLeft = 0; + int minimizeTop = 0; + if (mDockSide == WindowManager.DOCKED_TOP) { + minimizeTop = mBackground.getTop(); + } else if (mDockSide == WindowManager.DOCKED_LEFT) { + minimizeLeft = mBackground.getLeft(); + } else if (mDockSide == WindowManager.DOCKED_RIGHT) { + minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth(); + } + mMinimizedShadow.layout(minimizeLeft, minimizeTop, + minimizeLeft + mMinimizedShadow.getMeasuredWidth(), + minimizeTop + mMinimizedShadow.getMeasuredHeight()); if (changed) { mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom())); @@ -297,9 +322,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, return mDockSide != WindowManager.DOCKED_INVALID; } - public void stopDragging(int position, float velocity, boolean avoidDismissStart) { + public void stopDragging(int position, float velocity, boolean avoidDismissStart, + boolean logMetrics) { mHandle.setTouching(false, true /* animate */); - fling(position, velocity, avoidDismissStart); + fling(position, velocity, avoidDismissStart, logMetrics); mWindowManager.setSlippery(true); releaseBackground(); } @@ -325,6 +351,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private void updateDockSide() { mDockSide = mWindowManagerProxy.getDockSide(); + mMinimizedShadow.setDockSide(mDockSide); } private void initializeSnapAlgorithm() { @@ -396,22 +423,54 @@ public class DividerView extends FrameLayout implements OnTouchListener, mVelocityTracker.computeCurrentVelocity(1000); int position = calculatePosition(x, y); stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity() - : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */); + : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */, + true /* log */); mMoving = false; break; } return true; } + private void logResizeEvent(SnapTarget snapTarget) { + if (snapTarget == mSnapAlgorithm.getDismissStartTarget()) { + MetricsLogger.action( + mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide) + ? LOG_VALUE_UNDOCK_MAX_OTHER + : LOG_VALUE_UNDOCK_MAX_DOCKED); + } else if (snapTarget == mSnapAlgorithm.getDismissEndTarget()) { + MetricsLogger.action( + mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide) + ? LOG_VALUE_UNDOCK_MAX_OTHER + : LOG_VALUE_UNDOCK_MAX_DOCKED); + } else if (snapTarget == mSnapAlgorithm.getMiddleTarget()) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, + LOG_VALUE_RESIZE_50_50); + } else if (snapTarget == mSnapAlgorithm.getFirstSplitTarget()) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, + dockSideTopLeft(mDockSide) + ? LOG_VALUE_RESIZE_DOCKED_SMALLER + : LOG_VALUE_RESIZE_DOCKED_LARGER); + } else if (snapTarget == mSnapAlgorithm.getLastSplitTarget()) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, + dockSideTopLeft(mDockSide) + ? LOG_VALUE_RESIZE_DOCKED_LARGER + : LOG_VALUE_RESIZE_DOCKED_SMALLER); + } + } + private void convertToScreenCoordinates(MotionEvent event) { event.setLocation(event.getRawX(), event.getRawY()); } - private void fling(int position, float velocity, boolean avoidDismissStart) { + private void fling(int position, float velocity, boolean avoidDismissStart, + boolean logMetrics) { SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity); if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) { snapTarget = mSnapAlgorithm.getFirstSplitTarget(); } + if (logMetrics) { + logResizeEvent(snapTarget); + } ValueAnimator anim = getFlingAnimator(position, snapTarget); mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity); anim.start(); @@ -445,6 +504,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDockSide = WindowManager.DOCKED_INVALID; mCurrentAnimator = null; mEntranceAnimationRunning = false; + mExitAnimationRunning = false; EventBus.getDefault().send(new StoppedDragingEvent()); } }); @@ -538,6 +598,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, : mBackground.getWidth()); mBackground.setScaleX(MINIMIZE_DOCK_SCALE); } + mMinimizedShadow.setAlpha(minimized ? 1f : 0f); mDockedStackMinimized = minimized; } @@ -563,6 +624,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (!minimized) { mBackground.animate().withEndAction(mResetBackgroundRunnable); } + mMinimizedShadow.animate() + .alpha(minimized ? 1f : 0f) + .setInterpolator(Interpolators.ALPHA_IN) + .setDuration(animDuration) + .start(); mBackground.animate() .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setDuration(animDuration) @@ -575,6 +641,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mBackground.setPivotY(mBackground.getHeight() / 2); mBackground.setScaleX(1f); mBackground.setScaleY(1f); + mMinimizedShadow.setAlpha(0f); } @Override @@ -583,6 +650,13 @@ public class DividerView extends FrameLayout implements OnTouchListener, updateDisplayInfo(); } + + public void notifyDockSideChanged(int newDockSide) { + mDockSide = newDockSide; + mMinimizedShadow.setDockSide(mDockSide); + requestLayout(); + } + private void updateDisplayInfo() { final DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); @@ -654,6 +728,13 @@ public class DividerView extends FrameLayout implements OnTouchListener, mOtherTaskRect); mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null, mOtherTaskRect, null); + } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) { + calculateBoundsForPosition(taskPosition, + mDockSide, mDockedTaskRect); + calculateBoundsForPosition(mExitStartPosition, + DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect); + mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null, + mOtherTaskRect, null); } else if (taskPosition != TASK_POSITION_SAME) { calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide), mOtherRect); @@ -895,7 +976,9 @@ public class DividerView extends FrameLayout implements OnTouchListener, : mSnapAlgorithm.getDismissStartTarget(); // Don't start immediately - give a little bit time to settle the drag resize change. - stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */, + mExitAnimationRunning = true; + mExitStartPosition = getCurrentPosition(); + stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */, Interpolators.TOUCH_RESPONSE); // Vibrate after undocking diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java b/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java new file mode 100644 index 000000000000..ecff54fd907d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java @@ -0,0 +1,99 @@ +/* + * 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 + */ + +package com.android.systemui.stackdivider; + +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.View; +import android.view.WindowManager; + +import com.android.systemui.R; + +/** + * Shadow for the minimized dock state on homescreen. + */ +public class MinimizedDockShadow extends View { + + private final Paint mShadowPaint = new Paint(); + + private int mDockSide = WindowManager.DOCKED_INVALID; + + public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public void setDockSide(int dockSide) { + if (dockSide != mDockSide) { + mDockSide = dockSide; + updatePaint(getLeft(), getTop(), getRight(), getBottom()); + invalidate(); + } + } + + private void updatePaint(int left, int top, int right, int bottom) { + int startColor = mContext.getResources().getColor( + R.color.minimize_dock_shadow_start, null); + int endColor = mContext.getResources().getColor( + R.color.minimize_dock_shadow_end, null); + final int middleColor = Color.argb( + (Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0); + final int quarter = Color.argb( + (int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f), + 0, 0, 0); + if (mDockSide == WindowManager.DOCKED_TOP) { + mShadowPaint.setShader(new LinearGradient( + 0, 0, 0, bottom - top, + new int[] { startColor, middleColor, quarter, endColor }, + new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); + } else if (mDockSide == WindowManager.DOCKED_LEFT) { + mShadowPaint.setShader(new LinearGradient( + 0, 0, right - left, 0, + new int[] { startColor, middleColor, quarter, endColor }, + new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); + } else if (mDockSide == WindowManager.DOCKED_RIGHT) { + mShadowPaint.setShader(new LinearGradient( + right - left, 0, 0, 0, + new int[] { startColor, middleColor, quarter, endColor }, + new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + updatePaint(left, top, right, bottom); + invalidate(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 1b2393afcccf..11a7048cefa0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -63,6 +63,8 @@ import android.service.dreams.IDreamManager; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; +import android.service.vr.IVrManager; +import android.service.vr.IVrStateCallbacks; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -262,11 +264,24 @@ public abstract class BaseStatusBar extends SystemUI implements protected AssistManager mAssistManager; + protected boolean mVrMode; + @Override // NotificationData.Environment public boolean isDeviceProvisioned() { return mDeviceProvisioned; } + private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { + @Override + public void onVrStateChanged(boolean enabled) { + mVrMode = enabled; + } + }; + + public boolean isDeviceInVrMode() { + return mVrMode; + } + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { @@ -776,6 +791,14 @@ public abstract class BaseStatusBar extends SystemUI implements mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter, null, null); updateCurrentProfilesCache(); + + IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager")); + try { + vrManager.registerListener(mVrStateCallbacks); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register VR mode state listener: " + e); + } + } protected void notifyUserAboutHiddenNotifications() { @@ -1207,7 +1230,7 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public void toggleSplitScreen() { - toggleSplitScreenMode(); + toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */); } @Override @@ -1283,9 +1306,12 @@ public abstract class BaseStatusBar extends SystemUI implements /** * Toggle docking the app window * - * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise. + * @param metricsDockAction the action to log when docking is successful, or -1 to not log + * anything on successful docking + * @param metricsUndockAction the action to log when undocking, or -1 to not log anything when + * undocking */ - protected abstract boolean toggleSplitScreenMode(); + protected abstract void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction); /** Proxy for RecentsComponent */ @@ -2353,6 +2379,10 @@ public abstract class BaseStatusBar extends SystemUI implements } protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) { + if (isDeviceInVrMode()) { + return false; + } + if (mNotificationData.shouldFilterOut(sbn)) { if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey()); return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 86c1fca17a88..c2521b3d7d56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -65,8 +65,6 @@ import java.util.List; import static android.content.Context.LAYOUT_INFLATER_SERVICE; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; -import com.google.android.collect.Lists; - /** * Contains functionality for handling keyboard shortcuts. */ @@ -371,7 +369,7 @@ public final class KeyboardShortcuts { private KeyboardShortcutGroup getDefaultApplicationShortcuts() { final int userId = mContext.getUserId(); - List<KeyboardShortcutInfo> keyboardShortcutInfoAppItems = Lists.newArrayList(); + List<KeyboardShortcutInfo> keyboardShortcutInfoAppItems = new ArrayList<>(); // Assist. final AssistUtils assistUtils = new AssistUtils(mContext); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 5b005237e5d4..491ffde8071f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -348,6 +348,12 @@ public class NotificationContentView extends FrameLayout { setVisible(isShown()); } + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener); + } + private void setVisible(final boolean isVisible) { if (isVisible) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java index a5ebbbab36b3..9ed50224ed2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java @@ -232,8 +232,9 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC return; } final boolean isRtl = mParent.isLayoutRtl(); - final float left = isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0; - final float right = isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear); + // TODO No need to cast to float here once b/28050538 is fixed. + final float left = (float) (isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0); + final float right = (float) (isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear)); setTranslationX(onLeft ? left : right); mOnLeft = onLeft; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java index 03b51c653ac4..244536d22ef3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java @@ -240,6 +240,11 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo } @Override + public void dispatchDemoCommand(String command, Bundle args) { + // TODO: Car demo mode. + } + + @Override public boolean isPowerSave() { // Power save is not valid for the car, so always return false. return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index bb03454de0f1..583a63e21571 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -214,15 +214,14 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL < mContext.getResources().getDisplayMetrics().widthPixels / 2) { createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; } - boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds); + boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds, + MetricsEvent.ACTION_WINDOW_DOCK_SWIPE); if (docked) { mDragMode = dragMode; if (mDragMode == DRAG_MODE_DIVIDER) { mDivider.getView().startDragging(false /* animate */, true /* touching*/); } mDockWindowTouchSlopExceeded = true; - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE); - return true; } } @@ -250,7 +249,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL mIsVertical ? mVelocityTracker.getXVelocity() : mVelocityTracker.getYVelocity(), - true /* avoidDismissStart */); + true /* avoidDismissStart */, false /* logMetrics */); } else if (mDragMode == DRAG_MODE_RECENTS) { mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 68593484a862..581b611288ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -526,6 +526,10 @@ public class NavigationBarView extends LinearLayout { public void onDockedStackMinimizedChanged(boolean minimized, long animDuration) throws RemoteException { } + + @Override + public void onDockSideChanged(int newDockSide) throws RemoteException { + } }); } catch (RemoteException e) { Log.e(TAG, "Failed registering docked stack exists listener", e); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 75430ffe2d0a..5423f9d267d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1177,31 +1177,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return false; } - boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide() - == WindowManager.DOCKED_INVALID; - boolean dockedAtEnd = toggleSplitScreenMode(); - if (dockedAtEnd != initiallyDocked) { - int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS - : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS; - MetricsLogger.action(mContext, logAction); - return true; - } - return false; + toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS, + MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); + return true; } }; @Override - protected boolean toggleSplitScreenMode() { + protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { if (mRecents == null) { - return false; + return; } int dockSide = WindowManagerProxy.getInstance().getDockSide(); if (dockSide == WindowManager.DOCKED_INVALID) { - return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, - ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null); + mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, + ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction); } else { EventBus.getDefault().send(new UndockingTaskEvent()); - return false; + if (metricsUndockAction != -1) { + MetricsLogger.action(mContext, metricsUndockAction); + } } } @@ -1374,6 +1369,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private boolean shouldSuppressFullScreenIntent(String key) { + if (isDeviceInVrMode()) { + return true; + } + if (mPowerManager.isInteractive()) { return mNotificationData.shouldSuppressScreenOn(key); } else { @@ -3591,11 +3590,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, dispatchDemoCommandToView(command, args, R.id.clock); } if (modeChange || command.equals(COMMAND_BATTERY)) { - dispatchDemoCommandToView(command, args, R.id.battery); + mBatteryController.dispatchDemoCommand(command, args); } if (modeChange || command.equals(COMMAND_STATUS)) { mIconController.dispatchDemoCommand(command, args); - } if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { mNetworkController.dispatchDemoCommand(command, args); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 0ac2e7c4b8cd..823af36fff5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -139,6 +139,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); // listen for user / profile change. @@ -509,7 +510,8 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) { updateTTY(intent); } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) || - action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { + action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) || + action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) { updateQuietState(); updateManagedProfile(); } else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index ea64fd8e96e3..559436b10eed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -16,10 +16,12 @@ package com.android.systemui.statusbar.policy; +import com.android.systemui.DemoMode; + import java.io.FileDescriptor; import java.io.PrintWriter; -public interface BatteryController { +public interface BatteryController extends DemoMode { /** * Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 24207f3f35b9..5d734c682b49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -21,9 +21,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; +import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.util.Log; +import com.android.systemui.DemoMode; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -43,6 +45,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>(); private final PowerManager mPowerManager; private final Handler mHandler; + private final Context mContext; protected int mLevel; protected boolean mPluggedIn; @@ -52,17 +55,21 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private boolean mTestmode = false; public BatteryControllerImpl(Context context) { + mContext = context; mHandler = new Handler(); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + registerReceiver(); + updatePowerSave(); + } + + private void registerReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); filter.addAction(ACTION_LEVEL_TEST); - context.registerReceiver(this, filter); - - updatePowerSave(); + mContext.registerReceiver(this, filter); } @Override @@ -176,4 +183,28 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); } } + + private boolean mDemoMode; + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + if (!mDemoMode && command.equals(COMMAND_ENTER)) { + mDemoMode = true; + mContext.unregisterReceiver(this); + } else if (mDemoMode && command.equals(COMMAND_EXIT)) { + mDemoMode = false; + registerReceiver(); + updatePowerSave(); + } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { + String level = args.getString("level"); + String plugged = args.getString("plugged"); + if (level != null) { + mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); + } + if (plugged != null) { + mPluggedIn = Boolean.parseBoolean(plugged); + } + fireBatteryLevelChanged(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java index 6dd196b8b0c0..c4c64e7995ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java @@ -33,24 +33,29 @@ public class DataSaverController { } private void handleRestrictBackgroundChanged(boolean isDataSaving) { - final int N = mListeners.size(); - for (int i = 0; i < N; i++) { - mListeners.get(i).onDataSaverChanged(isDataSaving); + synchronized (mListeners) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onDataSaverChanged(isDataSaving); + } } } public void addListener(Listener listener) { - mListeners.add(listener); - if (mListeners.size() == 1) { - mPolicyManager.registerListener(mPolicyListener); + synchronized (mListeners) { + mListeners.add(listener); + if (mListeners.size() == 1) { + mPolicyManager.registerListener(mPolicyListener); + } } listener.onDataSaverChanged(isDataSaverEnabled()); } public void remListener(Listener listener) { - mListeners.remove(listener); - if (mListeners.size() == 0) { - mPolicyManager.unregisterListener(mPolicyListener); + synchronized (mListeners) { + mListeners.remove(listener); + if (mListeners.size() == 0) { + mPolicyManager.unregisterListener(mPolicyListener); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 7c5cdfbfcec1..8b52bf65a673 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -3799,6 +3799,7 @@ public class NotificationStackScrollLayout extends ViewGroup } else { getViewTreeObserver().removeOnPreDrawListener(mShadowUpdater); } + mContinuousShadowUpdate = continuousShadowUpdate; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 450001f3ab33..acef81b8ff1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -127,8 +127,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - protected boolean toggleSplitScreenMode() { - return false; + protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java index 748ee97c0621..ae104cd968ad 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java @@ -36,11 +36,15 @@ public class TunerActivity extends SettingsDrawerActivity implements super.onCreate(savedInstanceState); if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) { + boolean showDemoMode = getIntent().getAction().equals( + "com.android.settings.action.DEMO_MODE"); boolean showNightMode = getIntent().getBooleanExtra( NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false); + final PreferenceFragment fragment = showNightMode ? new NightModeFragment() + : showDemoMode ? new DemoModeFragment() + : new TunerFragment(); getFragmentManager().beginTransaction().replace(R.id.content_frame, - showNightMode ? new NightModeFragment() : new TunerFragment(), - TAG_TUNER).commit(); + fragment, TAG_TUNER).commit(); } } diff --git a/preloaded-classes b/preloaded-classes index be645d24c7fb..d8547694f864 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -12,6 +12,7 @@ [Landroid.animation.Keyframe; [Landroid.animation.PropertyValuesHolder; [Landroid.app.LoaderManagerImpl; +[Landroid.app.Notification$Action; [Landroid.content.ContentProviderResult; [Landroid.content.ContentValues; [Landroid.content.Intent; @@ -29,7 +30,6 @@ [Landroid.content.res.Configuration; [Landroid.content.res.StringBlock; [Landroid.content.res.XmlBlock; -[Landroid.database.Cursor; [Landroid.database.CursorWindow; [Landroid.database.sqlite.SQLiteConnection$Operation; [Landroid.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus; @@ -54,7 +54,6 @@ [Landroid.graphics.drawable.GradientDrawable$Orientation; [Landroid.graphics.drawable.LayerDrawable$ChildDrawable; [Landroid.graphics.drawable.RippleForeground; -[Landroid.hardware.display.WifiDisplay; [Landroid.hardware.soundtrigger.SoundTrigger$ConfidenceLevel; [Landroid.hardware.soundtrigger.SoundTrigger$Keyphrase; [Landroid.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionExtra; @@ -83,6 +82,10 @@ [Landroid.icu.util.ULocale$Category; [Landroid.icu.util.ULocale; [Landroid.media.AudioGain; +[Landroid.media.MediaCodecInfo$CodecCapabilities; +[Landroid.media.MediaCodecInfo$CodecProfileLevel; +[Landroid.media.MediaCodecInfo$Feature; +[Landroid.media.MediaCodecInfo; [Landroid.net.Network; [Landroid.net.NetworkInfo$DetailedState; [Landroid.net.NetworkInfo$State; @@ -109,7 +112,6 @@ [Landroid.text.method.TextKeyListener; [Landroid.text.style.AlignmentSpan; [Landroid.text.style.CharacterStyle; -[Landroid.text.style.ClickableSpan; [Landroid.text.style.LeadingMarginSpan; [Landroid.text.style.LineBackgroundSpan; [Landroid.text.style.LineHeightSpan; @@ -122,12 +124,11 @@ [Landroid.text.style.URLSpan; [Landroid.text.style.WrapTogetherSpan; [Landroid.util.LongSparseArray; -[Landroid.util.Pair; +[Landroid.util.Range; [Landroid.util.Rational; [Landroid.view.Choreographer$CallbackQueue; [Landroid.view.Display$ColorTransform; [Landroid.view.Display$Mode; -[Landroid.view.Display; [Landroid.view.HandlerActionQueue$HandlerAction; [Landroid.view.MenuItem; [Landroid.view.View; @@ -198,11 +199,13 @@ [Ljava.text.DateFormat$Field; [Ljava.text.Normalizer$Form; [Ljava.util.ArrayList; +[Ljava.util.Comparators$NaturalOrderComparator; [Ljava.util.Enumeration; [Ljava.util.Formatter$Flags; [Ljava.util.Formatter$FormatString; [Ljava.util.HashMap$HashMapEntry; [Ljava.util.Hashtable$HashtableEntry; +[Ljava.util.List; [Ljava.util.Locale$Category; [Ljava.util.Locale; [Ljava.util.Map$Entry; @@ -216,11 +219,8 @@ [Ljava.util.regex.Pattern; [Ljavax.crypto.Cipher$InitType; [Ljavax.crypto.Cipher$NeedToSet; -[Ljavax.microedition.khronos.egl.EGLConfig; [Ljavax.net.ssl.KeyManager; -[Ljavax.net.ssl.SSLSession; [Ljavax.net.ssl.TrustManager; -[Ljavax.security.auth.x500.X500Principal; [Ljavax.security.cert.X509Certificate; [Llibcore.io.ClassPathURLStreamHandler; [Llibcore.reflect.AnnotationMember$DefaultValues; @@ -307,12 +307,10 @@ android.animation.PathKeyframes android.animation.PathKeyframes$1 android.animation.PathKeyframes$2 android.animation.PathKeyframes$FloatKeyframesBase -android.animation.PathKeyframes$IntKeyframesBase android.animation.PathKeyframes$SimpleKeyframes android.animation.PropertyValuesHolder android.animation.PropertyValuesHolder$FloatPropertyValuesHolder android.animation.PropertyValuesHolder$IntPropertyValuesHolder -android.animation.PropertyValuesHolder$PropertyValues android.animation.RectEvaluator android.animation.StateListAnimator android.animation.StateListAnimator$1 @@ -328,7 +326,6 @@ android.app.Activity android.app.Activity$HostCallbacks android.app.ActivityManager android.app.ActivityManager$MemoryInfo -android.app.ActivityManager$RecentTaskInfo android.app.ActivityManager$RunningAppProcessInfo android.app.ActivityManager$RunningAppProcessInfo$1 android.app.ActivityManager$StackId @@ -348,7 +345,6 @@ android.app.ActivityThread$AppBindData android.app.ActivityThread$ApplicationThread android.app.ActivityThread$BindServiceData android.app.ActivityThread$ContextCleanupInfo -android.app.ActivityThread$CreateBackupAgentData android.app.ActivityThread$CreateServiceData android.app.ActivityThread$DropBoxReporter android.app.ActivityThread$EventLoggingReporter @@ -381,7 +377,7 @@ android.app.BackStackRecord$TransitionState android.app.ContextImpl android.app.ContextImpl$ApplicationContentResolver android.app.Dialog -android.app.Dialog$1 +android.app.Dialog$-void__init__android_content_Context_context_int_themeResId_boolean_createContextThemeWrapper_LambdaImpl0 android.app.Dialog$ListenersHandler android.app.DialogFragment android.app.DownloadManager @@ -402,8 +398,6 @@ android.app.IAlarmManager android.app.IAlarmManager$Stub android.app.IAlarmManager$Stub$Proxy android.app.IApplicationThread -android.app.IBackupAgent -android.app.IBackupAgent$Stub android.app.IInstrumentationWatcher android.app.IInstrumentationWatcher$Stub android.app.INotificationManager @@ -415,6 +409,9 @@ android.app.ITransientNotification android.app.ITransientNotification$Stub android.app.IUiAutomationConnection android.app.IUiAutomationConnection$Stub +android.app.IUiModeManager +android.app.IUiModeManager$Stub +android.app.IUiModeManager$Stub$Proxy android.app.Instrumentation android.app.IntentReceiverLeaked android.app.IntentService @@ -437,16 +434,21 @@ android.app.NativeActivity android.app.Notification android.app.Notification$1 android.app.Notification$Action +android.app.Notification$Action$1 android.app.Notification$BigTextStyle android.app.Notification$Builder +android.app.Notification$BuilderRemoteViews android.app.Notification$Style android.app.NotificationManager +android.app.OnActivityPausedListener android.app.PendingIntent android.app.PendingIntent$1 android.app.PendingIntent$CanceledException android.app.QueuedWork android.app.ReceiverRestrictedContext android.app.ResourcesManager +android.app.ResourcesManager$1 +android.app.ResourcesManager$ActivityResources android.app.ResultInfo android.app.ResultInfo$1 android.app.Service @@ -530,11 +532,15 @@ android.app.SystemServiceRegistry$68 android.app.SystemServiceRegistry$69 android.app.SystemServiceRegistry$7 android.app.SystemServiceRegistry$70 +android.app.SystemServiceRegistry$71 +android.app.SystemServiceRegistry$72 +android.app.SystemServiceRegistry$73 +android.app.SystemServiceRegistry$74 android.app.SystemServiceRegistry$8 android.app.SystemServiceRegistry$9 android.app.SystemServiceRegistry$CachedServiceFetcher android.app.SystemServiceRegistry$ServiceFetcher -android.app.SystemServiceRegistry$StaticOuterContextServiceFetcher +android.app.SystemServiceRegistry$StaticApplicationContextServiceFetcher android.app.SystemServiceRegistry$StaticServiceFetcher android.app.UiModeManager android.app.WallpaperManager @@ -542,10 +548,9 @@ android.app.admin.DevicePolicyManager android.app.admin.IDevicePolicyManager android.app.admin.IDevicePolicyManager$Stub android.app.admin.IDevicePolicyManager$Stub$Proxy -android.app.backup.BackupAgent -android.app.backup.BackupAgent$BackupServiceBinder -android.app.backup.BackupAgent$SharedPrefsSynchronizer -android.app.backup.BackupAgentHelper +android.app.admin.SecurityLog +android.app.admin.SecurityLog$SecurityEvent +android.app.admin.SecurityLog$SecurityEvent$1 android.app.backup.BackupDataInput android.app.backup.BackupDataInput$EntityHeader android.app.backup.BackupDataOutput @@ -554,9 +559,6 @@ android.app.backup.BackupHelperDispatcher$Header android.app.backup.FileBackupHelperBase android.app.backup.FullBackup android.app.backup.FullBackupDataOutput -android.app.backup.IBackupManager -android.app.backup.IBackupManager$Stub -android.app.backup.IBackupManager$Stub$Proxy android.app.job.JobScheduler android.app.trust.ITrustManager android.app.trust.ITrustManager$Stub @@ -566,9 +568,6 @@ android.app.usage.NetworkStatsManager android.app.usage.UsageStatsManager android.appwidget.AppWidgetManager android.appwidget.AppWidgetProvider -android.auditing.SecurityLog -android.auditing.SecurityLog$SecurityEvent -android.auditing.SecurityLog$SecurityEvent$1 android.bluetooth.BluetoothAdapter android.bluetooth.BluetoothAdapter$1 android.bluetooth.BluetoothManager @@ -585,6 +584,7 @@ android.content.AbstractThreadedSyncAdapter$SyncThread android.content.ActivityNotFoundException android.content.BroadcastReceiver android.content.BroadcastReceiver$PendingResult +android.content.BroadcastReceiver$PendingResult$1 android.content.ClipData android.content.ClipData$1 android.content.ClipData$Item @@ -600,7 +600,6 @@ android.content.ContentProvider$Transport android.content.ContentProviderClient android.content.ContentProviderNative android.content.ContentProviderOperation -android.content.ContentProviderOperation$Builder android.content.ContentProviderProxy android.content.ContentProviderResult android.content.ContentResolver @@ -637,7 +636,6 @@ android.content.IntentFilter$MalformedMimeTypeException android.content.IntentSender android.content.IntentSender$SendIntentException android.content.OperationApplicationException -android.content.PeriodicSync android.content.RestrictionsManager android.content.ServiceConnection android.content.SharedPreferences @@ -646,7 +644,6 @@ android.content.SharedPreferences$OnSharedPreferenceChangeListener android.content.SyncContext android.content.SyncRequest android.content.SyncRequest$1 -android.content.SyncRequest$Builder android.content.SyncResult android.content.SyncResult$1 android.content.SyncStats @@ -693,6 +690,7 @@ android.content.pm.ResolveInfo android.content.pm.ResolveInfo$1 android.content.pm.ServiceInfo android.content.pm.ServiceInfo$1 +android.content.pm.ShortcutManager android.content.pm.Signature android.content.pm.Signature$1 android.content.pm.UserInfo @@ -721,6 +719,8 @@ android.content.res.Resources android.content.res.Resources$NotFoundException android.content.res.Resources$Theme android.content.res.Resources$ThemeKey +android.content.res.ResourcesImpl +android.content.res.ResourcesImpl$ThemeImpl android.content.res.ResourcesKey android.content.res.StringBlock android.content.res.StringBlock$StyleIDs @@ -762,7 +762,6 @@ android.database.IContentObserver$Stub android.database.IContentObserver$Stub$Proxy android.database.MatrixCursor android.database.MatrixCursor$RowBuilder -android.database.MergeCursor android.database.Observable android.database.SQLException android.database.sqlite.DatabaseObjectNotClosedException @@ -775,7 +774,6 @@ android.database.sqlite.SQLiteConnection$PreparedStatementCache android.database.sqlite.SQLiteConnectionPool android.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus android.database.sqlite.SQLiteConnectionPool$ConnectionWaiter -android.database.sqlite.SQLiteConstraintException android.database.sqlite.SQLiteCursor android.database.sqlite.SQLiteCursorDriver android.database.sqlite.SQLiteCustomFunction @@ -807,7 +805,6 @@ android.ddm.DdmHandleProfiling android.ddm.DdmHandleThread android.ddm.DdmHandleViewDebug android.ddm.DdmRegister -android.graphics.AvoidXfermode android.graphics.Bitmap android.graphics.Bitmap$1 android.graphics.Bitmap$CompressFormat @@ -820,10 +817,10 @@ android.graphics.BlurMaskFilter android.graphics.Camera android.graphics.Canvas android.graphics.Canvas$EdgeType +android.graphics.Canvas$NoImagePreloadHolder android.graphics.CanvasProperty android.graphics.Color android.graphics.ColorFilter -android.graphics.ColorMatrix android.graphics.ColorMatrixColorFilter android.graphics.ComposePathEffect android.graphics.ComposeShader @@ -859,6 +856,7 @@ android.graphics.Paint$Cap android.graphics.Paint$FontMetrics android.graphics.Paint$FontMetricsInt android.graphics.Paint$Join +android.graphics.Paint$NoImagePreloadHolder android.graphics.Paint$Style android.graphics.PaintFlagsDrawFilter android.graphics.Path @@ -869,7 +867,6 @@ android.graphics.PathEffect android.graphics.PathMeasure android.graphics.Picture android.graphics.PixelFormat -android.graphics.PixelXorXfermode android.graphics.Point android.graphics.Point$1 android.graphics.PointF @@ -903,11 +900,14 @@ android.graphics.drawable.Animatable android.graphics.drawable.Animatable2 android.graphics.drawable.AnimatedStateListDrawable android.graphics.drawable.AnimatedStateListDrawable$AnimatedStateListState +android.graphics.drawable.AnimatedStateListDrawable$Transition android.graphics.drawable.AnimatedVectorDrawable android.graphics.drawable.AnimatedVectorDrawable$1 android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator +android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT +android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI android.graphics.drawable.AnimationDrawable android.graphics.drawable.AnimationDrawable$AnimationState android.graphics.drawable.BitmapDrawable @@ -976,12 +976,14 @@ android.hardware.Camera$CameraInfo android.hardware.Camera$Face android.hardware.ConsumerIrManager android.hardware.Sensor +android.hardware.SensorEvent android.hardware.SensorEventListener android.hardware.SensorManager android.hardware.SerialManager android.hardware.SerialPort android.hardware.SystemSensorManager android.hardware.SystemSensorManager$BaseEventQueue +android.hardware.SystemSensorManager$SensorEventQueue android.hardware.camera2.CameraCharacteristics$Key android.hardware.camera2.CameraManager android.hardware.camera2.CaptureRequest$Key @@ -1000,12 +1002,6 @@ android.hardware.display.IDisplayManager$Stub android.hardware.display.IDisplayManager$Stub$Proxy android.hardware.display.IDisplayManagerCallback android.hardware.display.IDisplayManagerCallback$Stub -android.hardware.display.WifiDisplay -android.hardware.display.WifiDisplay$1 -android.hardware.display.WifiDisplaySessionInfo -android.hardware.display.WifiDisplaySessionInfo$1 -android.hardware.display.WifiDisplayStatus -android.hardware.display.WifiDisplayStatus$1 android.hardware.fingerprint.FingerprintManager android.hardware.hdmi.HdmiControlManager android.hardware.input.IInputDevicesChangedListener @@ -1021,6 +1017,10 @@ android.hardware.input.InputManager$InputDevicesChangedListener # android.hardware.location.ActivityRecognitionHardware # android.hardware.location.IActivityRecognitionHardware # android.hardware.location.IActivityRecognitionHardware$Stub +android.hardware.location.ContextHubManager +android.hardware.location.ContextHubService +android.hardware.location.IContextHubService +android.hardware.location.IContextHubService$Stub android.hardware.radio.RadioManager android.hardware.radio.RadioManager$AmBandConfig android.hardware.radio.RadioManager$AmBandConfig$1 @@ -1046,6 +1046,7 @@ android.hardware.soundtrigger.SoundTrigger android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel$1 android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent +android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent$1 android.hardware.soundtrigger.SoundTrigger$GenericSoundModel android.hardware.soundtrigger.SoundTrigger$Keyphrase android.hardware.soundtrigger.SoundTrigger$Keyphrase$1 @@ -1070,7 +1071,6 @@ android.hardware.usb.IUsbManager$Stub android.hardware.usb.IUsbManager$Stub$Proxy android.hardware.usb.UsbDevice android.hardware.usb.UsbDeviceConnection -android.hardware.usb.UsbInterface android.hardware.usb.UsbManager android.hardware.usb.UsbRequest android.icu.impl.BMPSet @@ -1396,6 +1396,7 @@ android.media.AudioAttributes$Builder android.media.AudioDevicePort android.media.AudioDevicePortConfig android.media.AudioFormat +android.media.AudioFormat$1 android.media.AudioGain android.media.AudioGainConfig android.media.AudioHandle @@ -1412,8 +1413,6 @@ android.media.AudioPort android.media.AudioPortConfig android.media.AudioPortEventHandler android.media.AudioRecord -android.media.AudioRoutesInfo -android.media.AudioRoutesInfo$1 android.media.AudioRouting android.media.AudioSystem android.media.AudioTimestamp @@ -1425,21 +1424,13 @@ android.media.EncoderCapabilities android.media.ExifInterface android.media.IAudioFocusDispatcher android.media.IAudioFocusDispatcher$Stub -android.media.IAudioRoutesObserver -android.media.IAudioRoutesObserver$Stub android.media.IAudioService android.media.IAudioService$Stub android.media.IAudioService$Stub$Proxy android.media.IMediaHTTPConnection android.media.IMediaHTTPConnection$Stub -android.media.IMediaRouterClient -android.media.IMediaRouterClient$Stub -android.media.IMediaRouterService -android.media.IMediaRouterService$Stub android.media.IRecordingConfigDispatcher android.media.IRecordingConfigDispatcher$Stub -android.media.IRemoteVolumeObserver -android.media.IRemoteVolumeObserver$Stub android.media.Image android.media.ImageReader android.media.ImageReader$SurfaceImage @@ -1447,10 +1438,18 @@ android.media.ImageWriter android.media.ImageWriter$WriterSurfaceImage android.media.JetPlayer android.media.MediaCodec +android.media.MediaCodecInfo +android.media.MediaCodecInfo$AudioCapabilities +android.media.MediaCodecInfo$CodecCapabilities +android.media.MediaCodecInfo$CodecProfileLevel +android.media.MediaCodecInfo$EncoderCapabilities +android.media.MediaCodecInfo$Feature +android.media.MediaCodecInfo$VideoCapabilities android.media.MediaCodecList android.media.MediaCrypto android.media.MediaDrm android.media.MediaExtractor +android.media.MediaFormat android.media.MediaHTTPConnection android.media.MediaMetadataRetriever android.media.MediaMuxer @@ -1461,17 +1460,6 @@ android.media.MediaPlayer$OnPreparedListener android.media.MediaPlayer$OnSeekCompleteListener android.media.MediaRecorder android.media.MediaRouter -android.media.MediaRouter$Callback -android.media.MediaRouter$RouteCategory -android.media.MediaRouter$RouteInfo -android.media.MediaRouter$RouteInfo$1 -android.media.MediaRouter$Static -android.media.MediaRouter$Static$1 -android.media.MediaRouter$Static$Client -android.media.MediaRouter$VolumeChangeReceiver -android.media.MediaRouter$WifiDisplayStatusChangedReceiver -android.media.MediaRouterClientState -android.media.MediaRouterClientState$1 android.media.MediaScanner android.media.MediaSync android.media.PlaybackParams @@ -1479,9 +1467,10 @@ android.media.PlaybackParams$1 android.media.RemoteDisplay android.media.ResampleInputStream android.media.SubtitleController$Listener -android.media.ThumbnailUtils android.media.ToneGenerator -android.media.audiofx.AcousticEchoCanceler +android.media.Utils +android.media.Utils$1 +android.media.Utils$2 android.media.audiofx.AudioEffect android.media.audiopolicy.AudioMix android.media.audiopolicy.AudioMixingRule @@ -1504,13 +1493,13 @@ android.mtp.MtpStorageInfo android.net.ConnectivityManager android.net.ConnectivityManager$CallbackHandler android.net.ConnectivityManager$NetworkCallback +android.net.ConnectivityThread android.net.Credentials -android.net.DhcpResults -android.net.DhcpResults$1 android.net.EthernetManager android.net.IConnectivityManager android.net.IConnectivityManager$Stub android.net.IConnectivityManager$Stub$Proxy +android.net.INetworkPolicyManager android.net.IpPrefix android.net.IpPrefix$1 android.net.LinkAddress @@ -1545,8 +1534,6 @@ android.net.RouteInfo$1 android.net.SSLCertificateSocketFactory android.net.SSLCertificateSocketFactory$1 android.net.SSLSessionCache -android.net.StaticIpConfiguration -android.net.StaticIpConfiguration$1 android.net.TrafficStats android.net.Uri android.net.Uri$1 @@ -1584,10 +1571,16 @@ android.nfc.INfcAdapter$Stub android.nfc.INfcAdapter$Stub$Proxy android.nfc.INfcCardEmulation android.nfc.INfcCardEmulation$Stub +android.nfc.INfcCardEmulation$Stub$Proxy android.nfc.INfcFCardEmulation android.nfc.INfcFCardEmulation$Stub +android.nfc.INfcFCardEmulation$Stub$Proxy android.nfc.INfcTag android.nfc.INfcTag$Stub +android.nfc.INfcTag$Stub$Proxy +android.nfc.NfcActivityManager +android.nfc.NfcAdapter +android.nfc.NfcAdapter$1 android.nfc.NfcManager android.opengl.EGL14 android.opengl.EGLConfig @@ -1631,9 +1624,8 @@ android.os.CancellationSignal android.os.CancellationSignal$OnCancelListener android.os.CancellationSignal$Transport android.os.ConditionVariable -android.os.CpuUsageInfo -android.os.CpuUsageInfo$1 android.os.DeadObjectException +android.os.DeadSystemException android.os.Debug android.os.Debug$MemoryInfo android.os.Debug$MemoryInfo$1 @@ -1665,6 +1657,8 @@ android.os.IServiceManager android.os.IUserManager android.os.IUserManager$Stub android.os.IUserManager$Stub$Proxy +android.os.IVibratorService +android.os.IVibratorService$Stub android.os.Looper android.os.MemoryFile android.os.Message @@ -1679,10 +1673,13 @@ android.os.Parcel$1 android.os.ParcelFileDescriptor android.os.ParcelFileDescriptor$1 android.os.ParcelFileDescriptor$AutoCloseInputStream +android.os.ParcelFileDescriptor$AutoCloseOutputStream android.os.ParcelUuid android.os.Parcelable android.os.Parcelable$ClassLoaderCreator android.os.Parcelable$Creator +android.os.ParcelableParcel +android.os.ParcelableParcel$1 android.os.PatternMatcher android.os.PatternMatcher$1 android.os.PersistableBundle @@ -1691,6 +1688,7 @@ android.os.PowerManager android.os.PowerManager$WakeLock android.os.PowerManager$WakeLock$1 android.os.Process +android.os.RecoverySystem android.os.RemoteException android.os.ResultReceiver android.os.SELinux @@ -1726,24 +1724,26 @@ android.os.StrictMode$VmPolicy android.os.StrictMode$VmPolicy$Builder android.os.SystemClock android.os.SystemProperties +android.os.SystemVibrator android.os.Trace android.os.Trace$1 -android.os.TransactionTooLargeException android.os.UEventObserver android.os.UserHandle android.os.UserHandle$1 android.os.UserManager android.os.Vibrator android.os.ZygoteStartFailedEx +android.os.health.SystemHealthManager android.os.storage.IMountService android.os.storage.IMountService$Stub android.os.storage.IMountService$Stub$Proxy +android.os.storage.IObbActionListener +android.os.storage.IObbActionListener$Stub android.os.storage.StorageManager +android.os.storage.StorageManager$ObbActionListener android.os.storage.StorageVolume android.os.storage.StorageVolume$1 -android.preference.Preference$OnPreferenceChangeListener android.preference.PreferenceActivity -android.preference.PreferenceFragment android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback android.preference.PreferenceManager android.preference.PreferenceManager$OnPreferenceTreeClickListener @@ -1836,7 +1836,6 @@ android.system.StructUtsname android.system.UnixSocketAddress android.telecom.TelecomManager android.telephony.CarrierConfigManager -android.telephony.PhoneNumberUtils android.telephony.Rlog android.telephony.SubscriptionManager android.telephony.TelephonyManager @@ -1852,12 +1851,15 @@ android.text.Editable$Factory android.text.GetChars android.text.GraphicsOperations android.text.Html +android.text.Html$HtmlParser +android.text.HtmlToSpannedConverter android.text.Hyphenator android.text.InputFilter android.text.InputType android.text.Layout android.text.Layout$Alignment android.text.Layout$Directions +android.text.Layout$Ellipsizer android.text.MeasuredText android.text.NoCopySpan android.text.NoCopySpan$Concrete @@ -1916,7 +1918,6 @@ android.text.method.ScrollingMovementMethod android.text.method.SingleLineTransformationMethod android.text.method.TextKeyListener android.text.method.TextKeyListener$Capitalize -android.text.method.Touch android.text.method.TransformationMethod android.text.method.TransformationMethod2 android.text.style.AlignmentSpan @@ -1937,6 +1938,7 @@ android.text.style.SpellCheckSpan android.text.style.StyleSpan android.text.style.SuggestionSpan android.text.style.TabStopSpan +android.text.style.TextAppearanceSpan android.text.style.URLSpan android.text.style.UnderlineSpan android.text.style.UpdateAppearance @@ -1985,7 +1987,6 @@ android.util.EventLog android.util.EventLog$Event android.util.FloatProperty android.util.IntProperty -android.util.JsonReader android.util.LocaleList android.util.LocaleList$1 android.util.Log @@ -1993,7 +1994,6 @@ android.util.Log$1 android.util.Log$ImmediateLogWriter android.util.Log$TerribleFailureHandler android.util.LogPrinter -android.util.LongArray android.util.LongSparseArray android.util.LongSparseLongArray android.util.LruCache @@ -2006,15 +2006,16 @@ android.util.MutableLong android.util.Pair android.util.PathParser android.util.PathParser$PathData -android.util.Patterns android.util.Pools$Pool android.util.Pools$SimplePool android.util.Pools$SynchronizedPool android.util.Printer android.util.Property +android.util.Range android.util.Rational android.util.Singleton android.util.Size +android.util.SizeF android.util.Slog android.util.SparseArray android.util.SparseBooleanArray @@ -2031,6 +2032,7 @@ android.view.AbsSavedState$1 android.view.AbsSavedState$2 android.view.ActionMode android.view.ActionMode$Callback +android.view.ActionMode$Callback2 android.view.ActionProvider android.view.ActionProvider$SubUiVisibilityListener android.view.Choreographer @@ -2135,7 +2137,6 @@ android.view.PointerIcon$1 android.view.RenderNode android.view.RenderNodeAnimator android.view.RenderNodeAnimator$1 -android.view.RenderNodeAnimatorSetHelper android.view.SearchEvent android.view.SoundEffectConstants android.view.SubMenu @@ -2151,6 +2152,7 @@ android.view.SurfaceHolder$Callback2 android.view.SurfaceSession android.view.SurfaceView android.view.TextureView +android.view.TextureView$SurfaceTextureListener android.view.ThreadedRenderer android.view.ThreadedRenderer$HardwareDrawCallbacks android.view.ThreadedRenderer$ProcessInitializer @@ -2174,6 +2176,7 @@ android.view.View$AttachInfo android.view.View$AttachInfo$Callbacks android.view.View$BaseSavedState android.view.View$BaseSavedState$1 +android.view.View$CheckForLongPress android.view.View$CheckForTap android.view.View$ForegroundInfo android.view.View$ListenerInfo @@ -2258,10 +2261,10 @@ android.view.WindowAnimationFrameStats$1 android.view.WindowCallbacks android.view.WindowContentFrameStats android.view.WindowContentFrameStats$1 -android.view.WindowId android.view.WindowInsets android.view.WindowLeaked android.view.WindowManager +android.view.WindowManager$BadTokenException android.view.WindowManager$LayoutParams android.view.WindowManager$LayoutParams$1 android.view.WindowManagerGlobal @@ -2280,6 +2283,7 @@ android.view.accessibility.AccessibilityNodeProvider android.view.accessibility.AccessibilityRecord android.view.accessibility.CaptioningManager android.view.accessibility.CaptioningManager$1 +android.view.accessibility.CaptioningManager$CaptionStyle android.view.accessibility.CaptioningManager$CaptioningChangeListener android.view.accessibility.CaptioningManager$MyContentObserver android.view.accessibility.IAccessibilityManager @@ -2295,6 +2299,7 @@ android.view.animation.Animation$1 android.view.animation.Animation$2 android.view.animation.Animation$3 android.view.animation.Animation$AnimationListener +android.view.animation.Animation$Description android.view.animation.AnimationSet android.view.animation.AnimationUtils android.view.animation.BaseInterpolator @@ -2316,6 +2321,7 @@ android.view.inputmethod.EditorInfo$1 android.view.inputmethod.ExtractedText android.view.inputmethod.ExtractedText$1 android.view.inputmethod.InputConnection +android.view.inputmethod.InputConnectionInspector android.view.inputmethod.InputMethodManager android.view.inputmethod.InputMethodManager$1 android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper @@ -2323,15 +2329,17 @@ android.view.inputmethod.InputMethodManager$FinishedInputEventCallback android.view.inputmethod.InputMethodManager$H android.view.inputmethod.InputMethodManager$ImeInputEventSender android.view.inputmethod.InputMethodManager$PendingEvent -android.view.inputmethod.InputMethodSubtype android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener android.view.textservice.SpellCheckerSubtype android.view.textservice.SpellCheckerSubtype$1 android.view.textservice.TextServicesManager +android.webkit.IWebViewUpdateService +android.webkit.IWebViewUpdateService$Stub android.webkit.MimeTypeMap android.webkit.URLUtil android.webkit.WebSettings android.webkit.WebView +android.webkit.WebViewClient android.webkit.WebViewFactory android.webkit.WebViewFactory$MissingWebViewPackageException android.widget.AbsListView @@ -2348,6 +2356,7 @@ android.widget.AbsListView$SelectionBoundsAdjuster android.widget.AbsListView$WindowRunnnable android.widget.AbsSeekBar android.widget.AbsSpinner +android.widget.AbsSpinner$RecycleBin android.widget.AbsoluteLayout android.widget.ActionMenuPresenter android.widget.ActionMenuPresenter$1 @@ -2362,13 +2371,9 @@ android.widget.Adapter android.widget.AdapterView android.widget.AdapterView$AdapterDataSetObserver android.widget.AdapterView$OnItemClickListener -android.widget.AdapterView$OnItemLongClickListener android.widget.AdapterView$OnItemSelectedListener android.widget.ArrayAdapter android.widget.AutoCompleteTextView -android.widget.AutoCompleteTextView$DropDownItemClickListener -android.widget.AutoCompleteTextView$MyWatcher -android.widget.AutoCompleteTextView$PassThroughClickListener android.widget.BaseAdapter android.widget.Button android.widget.CheckBox @@ -2381,15 +2386,17 @@ android.widget.EditText android.widget.Editor android.widget.Editor$1 android.widget.Editor$2 -android.widget.Editor$3 android.widget.Editor$Blink android.widget.Editor$CursorAnchorInfoNotifier +android.widget.Editor$CursorController android.widget.Editor$EditOperation android.widget.Editor$EditOperation$1 android.widget.Editor$InputContentType android.widget.Editor$InputMethodState +android.widget.Editor$InsertionPointCursorController android.widget.Editor$PositionListener android.widget.Editor$ProcessTextIntentActionsHandler +android.widget.Editor$SelectionModifierCursorController android.widget.Editor$SpanController android.widget.Editor$SuggestionHelper android.widget.Editor$SuggestionHelper$SuggestionSpanComparator @@ -2439,6 +2446,19 @@ android.widget.RelativeLayout$DependencyGraph android.widget.RelativeLayout$DependencyGraph$Node android.widget.RelativeLayout$LayoutParams android.widget.RemoteViews +android.widget.RemoteViews$1 +android.widget.RemoteViews$2 +android.widget.RemoteViews$3 +android.widget.RemoteViews$Action +android.widget.RemoteViews$ActionException +android.widget.RemoteViews$BitmapCache +android.widget.RemoteViews$LayoutParamAction +android.widget.RemoteViews$MemoryUsageCounter +android.widget.RemoteViews$MutablePair +android.widget.RemoteViews$OnClickHandler +android.widget.RemoteViews$ReflectionAction +android.widget.RemoteViews$RuntimeAction +android.widget.RemoteViews$SetDrawableParameters android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback android.widget.RtlSpacingHelper android.widget.ScrollBarDrawable @@ -2451,7 +2471,10 @@ android.widget.Space android.widget.SpellChecker android.widget.SpellChecker$SpellParser android.widget.Spinner +android.widget.Spinner$SpinnerPopup android.widget.SpinnerAdapter +android.widget.Switch +android.widget.Switch$1 android.widget.TextView android.widget.TextView$3 android.widget.TextView$BufferType @@ -2460,6 +2483,7 @@ android.widget.TextView$CharWrapper android.widget.TextView$Drawables android.widget.TextView$OnEditorActionListener android.widget.TextView$SavedState +android.widget.TextView$SavedState$1 android.widget.ThemedSpinnerAdapter android.widget.Toast android.widget.Toast$TN @@ -2470,7 +2494,6 @@ android.widget.Toolbar$1 android.widget.Toolbar$2 android.widget.Toolbar$ExpandedActionViewMenuPresenter android.widget.Toolbar$LayoutParams -android.widget.ViewAnimator android.widget.WrapperListAdapter com.android.dex.Annotation com.android.dex.ClassData @@ -2511,9 +2534,10 @@ com.android.internal.app.AlertController$ButtonHandler com.android.internal.app.IAppOpsService com.android.internal.app.IAppOpsService$Stub com.android.internal.app.IAppOpsService$Stub$Proxy +com.android.internal.app.IBatteryStats +com.android.internal.app.IBatteryStats$Stub com.android.internal.app.IVoiceInteractor com.android.internal.app.IVoiceInteractor$Stub -com.android.internal.app.WindowDecorActionBar com.android.internal.appwidget.IAppWidgetService com.android.internal.appwidget.IAppWidgetService$Stub com.android.internal.appwidget.IAppWidgetService$Stub$Proxy @@ -2521,6 +2545,8 @@ com.android.internal.content.NativeLibraryHelper com.android.internal.content.ReferrerIntent com.android.internal.content.ReferrerIntent$1 com.android.internal.inputmethod.InputMethodUtils +com.android.internal.inputmethod.InputMethodUtils$1 +com.android.internal.inputmethod.LocaleUtils$LocaleExtractor com.android.internal.logging.AndroidConfig com.android.internal.logging.AndroidHandler com.android.internal.logging.AndroidHandler$1 @@ -2575,6 +2601,9 @@ com.android.internal.util.FastPrintWriter$DummyWriter com.android.internal.util.FastXmlSerializer com.android.internal.util.GrowingArrayUtils com.android.internal.util.LineBreakBufferedWriter +com.android.internal.util.MessageUtils +com.android.internal.util.NotificationColorUtil +com.android.internal.util.NotificationColorUtil$ColorUtilsFromCompat com.android.internal.util.Preconditions com.android.internal.util.VirtualRefBasePtr com.android.internal.util.XmlUtils @@ -2613,13 +2642,9 @@ com.android.internal.view.menu.MenuPresenter com.android.internal.view.menu.MenuPresenter$Callback com.android.internal.view.menu.MenuView com.android.internal.view.menu.ShowableListMenu -com.android.internal.widget.ActionBarOverlayLayout$ActionBarVisibilityCallback -com.android.internal.widget.AlertDialogLayout com.android.internal.widget.BackgroundFallback -com.android.internal.widget.ButtonBarLayout com.android.internal.widget.DecorContentParent com.android.internal.widget.DecorToolbar -com.android.internal.widget.DialogTitle com.android.internal.widget.EditableInputConnection com.android.internal.widget.ScrollBarUtils com.android.internal.widget.ToolbarWidgetWrapper @@ -2884,7 +2909,6 @@ dalvik.system.CloseGuard dalvik.system.CloseGuard$DefaultReporter dalvik.system.CloseGuard$Reporter dalvik.system.DalvikLogHandler -dalvik.system.DalvikLogging dalvik.system.DexClassLoader dalvik.system.DexFile dalvik.system.DexFile$DFEnum @@ -2911,6 +2935,7 @@ java.io.ByteArrayInputStream java.io.ByteArrayOutputStream java.io.CharArrayWriter java.io.Closeable +java.io.Console java.io.DataInput java.io.DataInputStream java.io.DataOutput @@ -2922,15 +2947,14 @@ java.io.ExpiringCache$Entry java.io.Externalizable java.io.File java.io.File$PathStatus -java.io.File$TempDirectory java.io.FileDescriptor +java.io.FileFilter java.io.FileInputStream java.io.FileInputStream$UseManualSkipException java.io.FileNotFoundException java.io.FileOutputStream java.io.FileReader java.io.FileSystem -java.io.FileWriter java.io.FilenameFilter java.io.FilterInputStream java.io.FilterOutputStream @@ -2941,7 +2965,6 @@ java.io.InputStream java.io.InputStreamReader java.io.InterruptedIOException java.io.InvalidObjectException -java.io.NotSerializableException java.io.ObjectInput java.io.ObjectInputStream java.io.ObjectInputStream$BlockDataInputStream @@ -3013,6 +3036,7 @@ java.lang.Enum$1 java.lang.EnumConstantNotPresentException java.lang.Error java.lang.Exception +java.lang.ExceptionInInitializerError java.lang.Float java.lang.FloatingDecimal java.lang.FloatingDecimal$1 @@ -3056,7 +3080,6 @@ java.lang.Runtime java.lang.RuntimeException java.lang.RuntimePermission java.lang.SecurityException -java.lang.SecurityManager java.lang.Short java.lang.Short$ShortCache java.lang.Shutdown @@ -3133,7 +3156,6 @@ java.math.BigDecimal java.math.BigInt java.math.BigInteger java.math.BitLevel -java.math.Multiplication java.math.NativeBN java.math.RoundingMode java.net.AbstractPlainDatagramSocketImpl @@ -3260,22 +3282,18 @@ java.security.AlgorithmConstraints java.security.AlgorithmParameters java.security.AlgorithmParametersSpi java.security.BasicPermission -java.security.BasicPermissionCollection java.security.CryptoPrimitive java.security.GeneralSecurityException java.security.Guard java.security.InvalidAlgorithmParameterException java.security.InvalidKeyException -java.security.InvalidParameterException java.security.Key java.security.KeyException java.security.KeyFactory java.security.KeyFactorySpi java.security.KeyManagementException -java.security.KeyPair java.security.KeyStore java.security.KeyStore$1 -java.security.KeyStore$LoadStoreParameter java.security.KeyStoreException java.security.KeyStoreSpi java.security.MessageDigest @@ -3285,6 +3303,7 @@ java.security.NoSuchAlgorithmException java.security.NoSuchProviderException java.security.Permission java.security.PermissionCollection +java.security.Permissions java.security.Principal java.security.PrivateKey java.security.PrivilegedAction @@ -3332,7 +3351,6 @@ java.security.cert.PKIXParameters java.security.cert.PKIXRevocationChecker java.security.cert.PolicyNode java.security.cert.TrustAnchor -java.security.cert.X509CRL java.security.cert.X509CertSelector java.security.cert.X509Certificate java.security.cert.X509Extension @@ -3342,7 +3360,6 @@ java.security.interfaces.ECKey java.security.interfaces.ECPrivateKey java.security.interfaces.ECPublicKey java.security.interfaces.RSAKey -java.security.interfaces.RSAPrivateCrtKey java.security.interfaces.RSAPrivateKey java.security.interfaces.RSAPublicKey java.security.spec.AlgorithmParameterSpec @@ -3351,19 +3368,14 @@ java.security.spec.ECFieldF2m java.security.spec.ECFieldFp java.security.spec.ECParameterSpec java.security.spec.ECPoint -java.security.spec.ECPrivateKeySpec java.security.spec.ECPublicKeySpec java.security.spec.EllipticCurve java.security.spec.EncodedKeySpec java.security.spec.InvalidKeySpecException java.security.spec.InvalidParameterSpecException java.security.spec.KeySpec -java.security.spec.PKCS8EncodedKeySpec -java.security.spec.RSAPrivateCrtKeySpec -java.security.spec.RSAPrivateKeySpec java.security.spec.RSAPublicKeySpec java.security.spec.X509EncodedKeySpec -java.sql.Timestamp java.text.AttributedCharacterIterator$Attribute java.text.CalendarBuilder java.text.Collator @@ -3401,7 +3413,9 @@ java.util.AbstractQueue java.util.AbstractSequentialList java.util.AbstractSet java.util.ArrayDeque +java.util.ArrayDeque$DeqIterator java.util.ArrayList +java.util.ArrayList$ArrayListSpliterator java.util.ArrayList$Itr java.util.ArrayList$ListItr java.util.ArrayList$SubList @@ -3414,6 +3428,7 @@ java.util.Collection java.util.Collections java.util.Collections$1 java.util.Collections$2 +java.util.Collections$3 java.util.Collections$AsLIFOQueue java.util.Collections$CheckedCollection java.util.Collections$CheckedList @@ -3456,6 +3471,14 @@ java.util.Collections$UnmodifiableSortedMap java.util.Collections$UnmodifiableSortedSet java.util.ComparableTimSort java.util.Comparator +java.util.Comparator$-java_util_Comparator_comparingDouble_java_util_function_ToDoubleFunction_keyExtractor_LambdaImpl0 +java.util.Comparator$-java_util_Comparator_comparingInt_java_util_function_ToIntFunction_keyExtractor_LambdaImpl0 +java.util.Comparator$-java_util_Comparator_comparingLong_java_util_function_ToLongFunction_keyExtractor_LambdaImpl0 +java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_LambdaImpl0 +java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_java_util_Comparator_keyComparator_LambdaImpl0 +java.util.Comparator$-java_util_Comparator_thenComparing_java_util_Comparator_other_LambdaImpl0 +java.util.Comparators$NaturalOrderComparator +java.util.Comparators$NullComparator java.util.ConcurrentModificationException java.util.Currency java.util.Date @@ -3464,7 +3487,6 @@ java.util.Dictionary java.util.DualPivotQuicksort java.util.EnumMap java.util.EnumMap$1 -java.util.EnumMap$EnumMapIterator java.util.EnumSet java.util.Enumeration java.util.EventListener @@ -3497,8 +3519,6 @@ java.util.Hashtable$Holder java.util.Hashtable$KeySet java.util.Hashtable$ValueCollection java.util.IdentityHashMap -java.util.IdentityHashMap$EntryIterator -java.util.IdentityHashMap$EntrySet java.util.IdentityHashMap$IdentityHashMapIterator java.util.IdentityHashMap$KeySet java.util.IllegalFormatException @@ -3538,7 +3558,6 @@ java.util.Random java.util.RandomAccess java.util.RandomAccessSubList java.util.RegularEnumSet -java.util.RegularEnumSet$EnumSetIterator java.util.ResourceBundle java.util.ResourceBundle$1 java.util.ResourceBundle$BundleReference @@ -3550,7 +3569,6 @@ java.util.ResourceBundle$Control$CandidateListCache java.util.ResourceBundle$LoaderReference java.util.ResourceBundle$RBClassLoader java.util.ResourceBundle$RBClassLoader$1 -java.util.Scanner java.util.ServiceLoader java.util.ServiceLoader$1 java.util.ServiceLoader$LazyIterator @@ -3558,6 +3576,17 @@ java.util.Set java.util.SimpleTimeZone java.util.SortedMap java.util.SortedSet +java.util.Spliterator +java.util.Spliterator$OfDouble +java.util.Spliterator$OfInt +java.util.Spliterator$OfLong +java.util.Spliterator$OfPrimitive +java.util.Spliterators +java.util.Spliterators$EmptySpliterator +java.util.Spliterators$EmptySpliterator$OfDouble +java.util.Spliterators$EmptySpliterator$OfInt +java.util.Spliterators$EmptySpliterator$OfLong +java.util.Spliterators$EmptySpliterator$OfRef java.util.Stack java.util.StringTokenizer java.util.SubList @@ -3569,12 +3598,10 @@ java.util.Timer$1 java.util.TimerTask java.util.TimerThread java.util.TreeMap -java.util.TreeMap$AscendingSubMap java.util.TreeMap$EntryIterator java.util.TreeMap$EntrySet java.util.TreeMap$KeyIterator java.util.TreeMap$KeySet -java.util.TreeMap$NavigableSubMap java.util.TreeMap$PrivateEntryIterator java.util.TreeMap$TreeMapEntry java.util.TreeMap$ValueIterator @@ -3595,14 +3622,12 @@ java.util.WeakHashMap$KeySet java.util.WeakHashMap$Values java.util.XMLUtils java.util.concurrent.AbstractExecutorService -java.util.concurrent.ArrayBlockingQueue java.util.concurrent.BlockingQueue java.util.concurrent.Callable java.util.concurrent.CancellationException java.util.concurrent.ConcurrentHashMap java.util.concurrent.ConcurrentHashMap$BaseIterator java.util.concurrent.ConcurrentHashMap$CollectionView -java.util.concurrent.ConcurrentHashMap$CounterCell java.util.concurrent.ConcurrentHashMap$ForwardingNode java.util.concurrent.ConcurrentHashMap$KeyIterator java.util.concurrent.ConcurrentHashMap$KeySetView @@ -3611,8 +3636,6 @@ java.util.concurrent.ConcurrentHashMap$Segment java.util.concurrent.ConcurrentHashMap$Traverser java.util.concurrent.ConcurrentHashMap$TreeBin java.util.concurrent.ConcurrentHashMap$TreeNode -java.util.concurrent.ConcurrentHashMap$ValueIterator -java.util.concurrent.ConcurrentHashMap$ValuesView java.util.concurrent.ConcurrentLinkedQueue java.util.concurrent.ConcurrentLinkedQueue$Node java.util.concurrent.ConcurrentMap @@ -3689,6 +3712,16 @@ java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock java.util.concurrent.locks.ReentrantReadWriteLock$Sync java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock +java.util.function.BiConsumer +java.util.function.BiFunction +java.util.function.Consumer +java.util.function.Function +java.util.function.Predicate +java.util.function.Supplier +java.util.function.ToDoubleFunction +java.util.function.ToIntFunction +java.util.function.ToLongFunction +java.util.function.UnaryOperator java.util.jar.JarEntry java.util.jar.JarFile java.util.jar.JarFile$1 @@ -3709,15 +3742,19 @@ java.util.logging.LogManager$LoggerContext$1 java.util.logging.LogManager$LoggerWeakRef java.util.logging.LogManager$RootLogger java.util.logging.LogManager$SystemLoggerContext -java.util.logging.LogRecord java.util.logging.Logger java.util.logging.LoggingPermission java.util.logging.LoggingProxyImpl +java.util.prefs.AbstractPreferences +java.util.prefs.Preferences java.util.regex.MatchResult java.util.regex.Matcher java.util.regex.Pattern java.util.regex.PatternSyntaxException java.util.spi.LocaleServiceProvider +java.util.stream.BaseStream +java.util.stream.Stream +java.util.stream.StreamSupport java.util.zip.Adler32 java.util.zip.CRC32 java.util.zip.CheckedInputStream @@ -3748,7 +3785,6 @@ javax.crypto.Cipher$Transform javax.crypto.CipherSpi javax.crypto.IllegalBlockSizeException javax.crypto.JceSecurity -javax.crypto.Mac javax.crypto.NoSuchPaddingException javax.crypto.NullCipher javax.crypto.SecretKey @@ -3757,10 +3793,6 @@ javax.crypto.spec.IvParameterSpec javax.crypto.spec.SecretKeySpec javax.microedition.khronos.egl.EGL javax.microedition.khronos.egl.EGL10 -javax.microedition.khronos.egl.EGLConfig -javax.microedition.khronos.egl.EGLContext -javax.microedition.khronos.egl.EGLDisplay -javax.microedition.khronos.egl.EGLSurface javax.microedition.khronos.opengles.GL javax.microedition.khronos.opengles.GL10 javax.microedition.khronos.opengles.GL10Ext @@ -3771,7 +3803,6 @@ javax.net.DefaultSocketFactory javax.net.ServerSocketFactory javax.net.SocketFactory javax.net.ssl.ExtendedSSLSession -javax.net.ssl.HandshakeCompletedEvent javax.net.ssl.HandshakeCompletedListener javax.net.ssl.HostnameVerifier javax.net.ssl.HttpsURLConnection @@ -3779,23 +3810,20 @@ javax.net.ssl.KeyManager javax.net.ssl.KeyManagerFactory javax.net.ssl.KeyManagerFactory$1 javax.net.ssl.KeyManagerFactorySpi +javax.net.ssl.SNIHostName +javax.net.ssl.SNIServerName javax.net.ssl.SSLContext javax.net.ssl.SSLContextSpi javax.net.ssl.SSLEngine javax.net.ssl.SSLException -javax.net.ssl.SSLHandshakeException javax.net.ssl.SSLParameters javax.net.ssl.SSLPeerUnverifiedException javax.net.ssl.SSLProtocolException -javax.net.ssl.SSLServerSocket javax.net.ssl.SSLServerSocketFactory javax.net.ssl.SSLSession -javax.net.ssl.SSLSessionBindingEvent -javax.net.ssl.SSLSessionBindingListener javax.net.ssl.SSLSessionContext javax.net.ssl.SSLSocket javax.net.ssl.SSLSocketFactory -javax.net.ssl.SSLSocketFactory$1 javax.net.ssl.TrustManager javax.net.ssl.TrustManagerFactory javax.net.ssl.TrustManagerFactory$1 @@ -3841,7 +3869,6 @@ libcore.io.MemoryMappedFile libcore.io.NioBufferIterator libcore.io.Os libcore.io.Posix -libcore.math.MathUtils libcore.net.NetworkSecurityPolicy libcore.net.NetworkSecurityPolicy$DefaultNetworkSecurityPolicy libcore.net.UriCodec @@ -3857,7 +3884,6 @@ libcore.reflect.InternalNames libcore.reflect.ListOfTypes libcore.reflect.ListOfVariables libcore.reflect.ParameterizedTypeImpl -libcore.reflect.TypeVariableImpl libcore.reflect.Types libcore.util.BasicLruCache libcore.util.CharsetUtils @@ -3866,7 +3892,6 @@ libcore.util.EmptyArray libcore.util.NativeAllocationRegistry libcore.util.NativeAllocationRegistry$CleanerRunner libcore.util.NativeAllocationRegistry$CleanerThunk -libcore.util.Objects libcore.util.ZoneInfo libcore.util.ZoneInfo$CheckedArithmeticException libcore.util.ZoneInfo$WallTime @@ -3892,11 +3917,8 @@ org.apache.http.HttpRequest org.apache.http.HttpResponse org.apache.http.HttpVersion org.apache.http.NameValuePair -org.apache.http.ProtocolException org.apache.http.ProtocolVersion -org.apache.http.ReasonPhraseCatalog org.apache.http.StatusLine -org.apache.http.client.ClientProtocolException org.apache.http.client.HttpClient org.apache.http.client.ResponseHandler org.apache.http.client.methods.AbortableHttpRequest @@ -3905,26 +3927,15 @@ org.apache.http.client.methods.HttpGet org.apache.http.client.methods.HttpPost org.apache.http.client.methods.HttpRequestBase org.apache.http.client.methods.HttpUriRequest -org.apache.http.client.utils.URLEncodedUtils org.apache.http.conn.ClientConnectionManager org.apache.http.conn.ConnectTimeoutException -org.apache.http.conn.params.ConnManagerPNames -org.apache.http.conn.params.ConnManagerParams -org.apache.http.conn.params.ConnManagerParams$1 -org.apache.http.conn.params.ConnPerRoute -org.apache.http.conn.scheme.LayeredSocketFactory -org.apache.http.conn.scheme.SocketFactory org.apache.http.entity.AbstractHttpEntity -org.apache.http.entity.BasicHttpEntity org.apache.http.entity.ByteArrayEntity -org.apache.http.impl.client.EntityEnclosingRequestWrapper -org.apache.http.impl.client.RequestWrapper org.apache.http.impl.cookie.DateParseException org.apache.http.impl.cookie.DateUtils org.apache.http.message.AbstractHttpMessage org.apache.http.message.BasicHeader org.apache.http.message.BasicHttpResponse -org.apache.http.message.BasicNameValuePair org.apache.http.message.BasicStatusLine org.apache.http.message.HeaderGroup org.apache.http.params.AbstractHttpParams @@ -3933,6 +3944,18 @@ org.apache.http.params.CoreConnectionPNames org.apache.http.params.HttpConnectionParams org.apache.http.params.HttpParams org.apache.http.protocol.HttpContext +org.ccil.cowan.tagsoup.AttributesImpl +org.ccil.cowan.tagsoup.AutoDetector +org.ccil.cowan.tagsoup.Element +org.ccil.cowan.tagsoup.ElementType +org.ccil.cowan.tagsoup.HTMLModels +org.ccil.cowan.tagsoup.HTMLScanner +org.ccil.cowan.tagsoup.HTMLSchema +org.ccil.cowan.tagsoup.Parser +org.ccil.cowan.tagsoup.Parser$1 +org.ccil.cowan.tagsoup.ScanHandler +org.ccil.cowan.tagsoup.Scanner +org.ccil.cowan.tagsoup.Schema org.json.JSON org.json.JSONArray org.json.JSONException @@ -3954,6 +3977,7 @@ org.xml.sax.SAXException org.xml.sax.SAXNotRecognizedException org.xml.sax.SAXNotSupportedException org.xml.sax.XMLReader +org.xml.sax.ext.LexicalHandler org.xml.sax.helpers.DefaultHandler org.xmlpull.v1.XmlPullParser org.xmlpull.v1.XmlPullParserException diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index ea3cffe3c945..afea7f3aa980 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2138,6 +2138,20 @@ message MetricsEvent { // Settings > Apps > Gear > Special Access > Premium SMS access PREMIUM_SMS_ACCESS = 388; + // Logged when the user resizes the docked stack. Arguments: + // 0: Split 50:50 + // 1: Docked smaller + // 2: Docked larger + ACTION_WINDOW_DOCK_RESIZE = 389; + + // User exits split-screen by dragging the divider to the side of the screen. Arguments + // 0: Docked gets maximized + // 1: Fullscreen gets maximized + ACTION_WINDOW_UNDOCK_MAX = 390; + + // User tried to dock an unresizable app. + ACTION_WINDOW_DOCK_UNRESIZABLE = 391; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java index 9ec6e8daf429..04ea8e5a663f 100644 --- a/rs/java/android/renderscript/Allocation.java +++ b/rs/java/android/renderscript/Allocation.java @@ -58,6 +58,7 @@ public class Allocation extends BaseObj { private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16; Type mType; + boolean mOwningType = false; Bitmap mBitmap; int mUsage; Allocation mAdaptedAllocation; @@ -383,13 +384,16 @@ public class Allocation extends BaseObj { guard.open("destroy"); } - Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) { + Allocation(long id, RenderScript rs, Type t, boolean owningType, int usage, MipmapControl mips) { this(id, rs, t, usage); + mOwningType = owningType; mMipmapControl = mips; } protected void finalize() throws Throwable { RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize); + // Set mType null to avoid double-destroying it in case its finalizer races ahead + mType = null; super.finalize(); } @@ -1578,6 +1582,9 @@ public class Allocation extends BaseObj { mRS.finish(); // Necessary because resize is fifoed and update is async. long typeID = mRS.nAllocationGetType(getID(mRS)); + // Sets zero the mID so that the finalizer of the old mType value won't + // destroy the native object that is being reused. + mType.setID(0); mType = new Type(typeID, mRS); mType.updateFromNative(); updateCacheInfo(mType); @@ -1921,7 +1928,7 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } - return new Allocation(id, rs, type, usage, mips); + return new Allocation(id, rs, type, false, usage, mips); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1979,7 +1986,7 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } - return new Allocation(id, rs, t, usage, MipmapControl.MIPMAP_NONE); + return new Allocation(id, rs, t, true, usage, MipmapControl.MIPMAP_NONE); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -2068,7 +2075,7 @@ public class Allocation extends BaseObj { } // keep a reference to the Bitmap around to prevent GC - Allocation alloc = new Allocation(id, rs, t, usage, mips); + Allocation alloc = new Allocation(id, rs, t, true, usage, mips); alloc.setBitmap(b); return alloc; } @@ -2078,7 +2085,7 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Load failed."); } - return new Allocation(id, rs, t, usage, mips); + return new Allocation(id, rs, t, true, usage, mips); } finally { Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -2150,7 +2157,7 @@ public class Allocation extends BaseObj { } for (int i=1; i<numAlloc; i++) { - mAllocationArray[i] = createFromAllcation(rs, mAllocationArray[0]); + mAllocationArray[i] = createFromAllocation(rs, mAllocationArray[0]); } return mAllocationArray; } finally { @@ -2169,7 +2176,7 @@ public class Allocation extends BaseObj { * @param alloc RenderScript Allocation describing data layout. * @return Allocation sharing the same data structure. */ - static Allocation createFromAllcation(RenderScript rs, Allocation alloc) { + static Allocation createFromAllocation(RenderScript rs, Allocation alloc) { try { Trace.traceBegin(RenderScript.TRACE_TAG, "createFromAllcation"); rs.validate(); @@ -2184,7 +2191,7 @@ public class Allocation extends BaseObj { if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } - Allocation outAlloc = new Allocation(id, rs, type, usage, mips); + Allocation outAlloc = new Allocation(id, rs, type, false, usage, mips); if ((usage & USAGE_IO_INPUT) != 0) { outAlloc.shareBufferQueue(alloc); } @@ -2360,7 +2367,7 @@ public class Allocation extends BaseObj { if(id == 0) { throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); } - return new Allocation(id, rs, t, usage, mips); + return new Allocation(id, rs, t, true, usage, mips); } /** @@ -2605,6 +2612,13 @@ public class Allocation extends BaseObj { if((mUsage & USAGE_IO_OUTPUT) != 0) { setSurface(null); } + + if (mType != null && mOwningType) { + mType.destroy(); + mType = null; + } + super.destroy(); } + } diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java index 219f16b91baf..35ae8b406e45 100644 --- a/rs/java/android/renderscript/ScriptGroup.java +++ b/rs/java/android/renderscript/ScriptGroup.java @@ -187,6 +187,23 @@ public final class ScriptGroup extends BaseObj { guard.open("destroy"); } + /** + * Destroys this Closure and the Allocation for its return value + */ + public void destroy() { + super.destroy(); + if (mReturnValue != null) { + mReturnValue.destroy(); + } + } + + protected void finalize() throws Throwable { + // Set null mReturnValue to avoid double-destroying it, in case its + // finalizer races ahead. + mReturnValue = null; + super.finalize(); + } + private void retrieveValueAndDependenceInfo(RenderScript rs, int index, Script.FieldID fid, Object obj, long[] values, int[] sizes, @@ -1015,6 +1032,8 @@ public final class ScriptGroup extends BaseObj { throw new RSIllegalArgumentException("invalid script group name"); } ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs); + mClosures = new ArrayList<Closure>(); + mInputs = new ArrayList<Input>(); return ret; } @@ -1042,4 +1061,20 @@ public final class ScriptGroup extends BaseObj { } + /** + * Destroy this ScriptGroup and all Closures in it + */ + public void destroy() { + super.destroy(); + for(Closure c : mClosures) { + c.destroy(); + } + } + + protected void finalize() throws Throwable { + // Clear out the list mClosures to avoid double-destroying the closures, + // in case their finalizers race ahead. + mClosures.clear(); + super.finalize(); + } } diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java index fb1ef37141b0..b2196bf946e2 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java @@ -156,10 +156,10 @@ class MagnificationController { final float offsetY = sentSpec.offsetY; // Compute the new center and update spec as needed. - final float centerX = (mMagnifiedBounds.width() / 2.0f - offsetX) / scale - + mMagnifiedBounds.left; - final float centerY = (mMagnifiedBounds.height() / 2.0f - offsetY) / scale - + mMagnifiedBounds.top; + final float centerX = (mMagnifiedBounds.width() / 2.0f + + mMagnifiedBounds.left - offsetX) / scale; + final float centerY = (mMagnifiedBounds.height() / 2.0f + + mMagnifiedBounds.top - offsetY) / scale; if (updateSpec) { setScaleAndCenter(scale, centerX, centerY, false); } else { @@ -256,7 +256,7 @@ class MagnificationController { public float getCenterX() { synchronized (mLock) { return (mMagnifiedBounds.width() / 2.0f - - getOffsetX()) / getScale() + mMagnifiedBounds.left; + + mMagnifiedBounds.left - getOffsetX()) / getScale(); } } @@ -279,7 +279,7 @@ class MagnificationController { public float getCenterY() { synchronized (mLock) { return (mMagnifiedBounds.height() / 2.0f - - getOffsetY()) / getScale() + mMagnifiedBounds.top; + + mMagnifiedBounds.top - getOffsetY()) / getScale(); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 428e192bb055..2ccc3fe80edf 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2025,11 +2025,15 @@ public class ConnectivityService extends IConnectivityManager.Stub default: return false; case NetworkMonitor.EVENT_NETWORK_TESTED: { - NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; - if (isLiveNetworkAgent(nai, msg.what)) { + final NetworkAgentInfo nai; + synchronized (mNetworkForNetId) { + nai = mNetworkForNetId.get(msg.arg2); + } + if (nai != null) { final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); - if (DBG) log(nai.name() + " validation " + (valid ? " passed" : "failed")); + if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") + + (msg.obj == null ? "" : " with redirect to " + (String)msg.obj)); if (valid != nai.lastValidated) { final int oldScore = nai.getCurrentScore(); nai.lastValidated = valid; @@ -2040,10 +2044,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } updateInetCondition(nai); // Let the NetworkAgent know the state of its network + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj); nai.asyncChannel.sendMessage( - android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS, + NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), - 0, null); + 0, redirectUrlBundle); } break; } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 22cc066434dd..544e6455fab5 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2966,16 +2966,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId); - if (mSubtypeSwitchedByShortCutToast != null) { - mSubtypeSwitchedByShortCutToast.cancel(); - mSubtypeSwitchedByShortCutToast = null; - } - if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) { - // IME window is shown. The user should be able to visually understand that the - // subtype is changed in most of cases. To avoid UI overlap, we do not show a toast - // in this case. - return; - } final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId); if (newInputMethodInfo == null) { return; @@ -2983,8 +2973,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext, newInputMethodInfo, mCurrentSubtype); if (!TextUtils.isEmpty(toastText)) { - mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(), - Toast.LENGTH_SHORT); + if (mSubtypeSwitchedByShortCutToast == null) { + mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText, + Toast.LENGTH_SHORT); + } else { + mSubtypeSwitchedByShortCutToast.setText(toastText); + } mSubtypeSwitchedByShortCutToast.show(); } } diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java index d136f1af7654..9ab63003c8dc 100644 --- a/services/core/java/com/android/server/LockSettingsStorage.java +++ b/services/core/java/com/android/server/LockSettingsStorage.java @@ -401,7 +401,8 @@ class LockSettingsStorage { return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE); } - private String getChildProfileLockFile(int userId) { + @VisibleForTesting + String getChildProfileLockFile(int userId) { return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE); } diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 7db9be20e95f..6009984842f4 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -243,7 +243,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo log("Problem parsing message " + e); } finally { if (releaseWl) { - mWakeLock.acquire(); + mWakeLock.release(); } } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 05e4245fd175..47918187e22a 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -91,6 +91,8 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.LocalServices; +import com.android.server.SystemService; + import com.google.android.collect.Lists; import com.google.android.collect.Sets; @@ -127,9 +129,34 @@ import java.util.concurrent.atomic.AtomicReference; public class AccountManagerService extends IAccountManager.Stub implements RegisteredServicesCacheListener<AuthenticatorDescription> { - private static final String TAG = "AccountManagerService"; + public static class Lifecycle extends SystemService { + private AccountManagerService mService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new AccountManagerService(getContext()); + publishBinderService(Context.ACCOUNT_SERVICE, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + mService.systemReady(); + } + } + + @Override + public void onUnlockUser(int userHandle) { + mService.onUnlockUser(userHandle); + } + } + private static final String DATABASE_NAME = "accounts.db"; private static final int PRE_N_DATABASE_VERSION = 9; private static final int CE_DATABASE_VERSION = 10; @@ -340,15 +367,12 @@ public class AccountManagerService IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_REMOVED); - userFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_USER_REMOVED.equals(action)) { onUserRemoved(intent); - } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { - onUserUnlocked(intent); } } }, UserHandle.ALL, userFilter, null, null); @@ -654,7 +678,10 @@ public class AccountManagerService @VisibleForTesting void onUserUnlocked(Intent intent) { - int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); + } + + void onUnlockUser(int userId) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "onUserUnlocked " + userId); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3ec51e3dfa42..c01b4f519ad4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8792,6 +8792,7 @@ public final class ActivityManagerService extends ActivityManagerNative rti.bounds = new Rect(tr.mBounds); } rti.isDockable = tr.canGoInDockedStack(); + rti.resizeMode = tr.mResizeMode; ActivityRecord base = null; ActivityRecord top = null; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 2e9947a9e0d9..837a1c1f1a21 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -4776,6 +4776,7 @@ final class ActivityStack { ci.numActivities = numActivities; ci.numRunning = numRunning; ci.isDockable = task.canGoInDockedStack(); + ci.resizeMode = task.mResizeMode; list.add(ci); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index d34e8fc461ea..53c602408d5d 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -4248,6 +4248,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // Work Challenge is present) let startActivityInPackage handle the intercepting. if (!mService.mUserController.shouldConfirmCredentials(task.userId) && task.getRootActivity() != null) { + mActivityMetricsLogger.notifyActivityLaunching(); mService.moveTaskToFrontLocked(task.taskId, 0, bOptions); // If we are launching the task in the docked stack, put it into resizing mode so diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index bbb162e7c16f..d33075634ca0 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -120,8 +120,9 @@ public class NetworkMonitor extends StateMachine { /** * Inform ConnectivityService that the network has been tested. - * obj = NetworkAgentInfo + * obj = String representing URL that Internet probe was redirect to, if it was redirected. * arg1 = One of the NETWORK_TESTED_RESULT_* constants. + * arg2 = NetID. */ public static final int EVENT_NETWORK_TESTED = BASE + 2; @@ -334,8 +335,8 @@ public class NetworkMonitor extends StateMachine { mDontDisplaySigninNotification = true; mUserDoesNotWant = true; mConnectivityServiceHandler.sendMessage(obtainMessage( - EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0, - mNetworkAgentInfo)); + EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, + mNetworkAgentInfo.network.netId, null)); // TODO: Should teardown network. mUidResponsibleForReeval = 0; transitionTo(mEvaluatingState); @@ -358,7 +359,7 @@ public class NetworkMonitor extends StateMachine { CaptivePortalStateChangeEvent.logEvent( CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED); mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, - NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo)); + NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null)); } @Override @@ -412,6 +413,21 @@ public class NetworkMonitor extends StateMachine { } } + /** + * Result of calling isCaptivePortal(). + * @hide + */ + @VisibleForTesting + public static final class CaptivePortalProbeResult { + final int mHttpResponseCode; // HTTP response code returned from Internet probe. + final String mRedirectUrl; // Redirect destination returned from Internet probe. + + public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) { + mHttpResponseCode = httpResponseCode; + mRedirectUrl = redirectUrl; + } + } + // Being in the EvaluatingState State indicates the Network is being evaluated for internet // connectivity, or that the user has indicated that this network is unwanted. private class EvaluatingState extends State { @@ -464,19 +480,23 @@ public class NetworkMonitor extends StateMachine { // IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine // will be unresponsive. isCaptivePortal() could be executed on another Thread // if this is found to cause problems. - int httpResponseCode = isCaptivePortal(); + CaptivePortalProbeResult probeResult = isCaptivePortal(); CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId, - httpResponseCode); - if (httpResponseCode == 204) { + probeResult.mHttpResponseCode); + if (probeResult.mHttpResponseCode == 204) { transitionTo(mValidatedState); - } else if (httpResponseCode >= 200 && httpResponseCode <= 399) { + } else if (probeResult.mHttpResponseCode >= 200 && + probeResult.mHttpResponseCode <= 399) { + mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, + NETWORK_TEST_RESULT_INVALID, mNetworkAgentInfo.network.netId, + probeResult.mRedirectUrl)); transitionTo(mCaptivePortalState); } else { final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); sendMessageDelayed(msg, mReevaluateDelayMs); mConnectivityServiceHandler.sendMessage(obtainMessage( - EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0, - mNetworkAgentInfo)); + EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, + mNetworkAgentInfo.network.netId, probeResult.mRedirectUrl)); if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) { // Don't continue to blame UID forever. TrafficStats.clearThreadStatsUid(); @@ -533,8 +553,6 @@ public class NetworkMonitor extends StateMachine { @Override public void enter() { - mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, - NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); // Don't annoy user with sign-in notifications. if (mDontDisplaySigninNotification) return; // Create a CustomIntentReceiver that sends us a @@ -639,11 +657,12 @@ public class NetworkMonitor extends StateMachine { * Returns HTTP response code. */ @VisibleForTesting - protected int isCaptivePortal() { - if (!mIsCaptivePortalCheckEnabled) return 204; + protected CaptivePortalProbeResult isCaptivePortal() { + if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null); HttpURLConnection urlConnection = null; int httpResponseCode = 599; + String redirectUrl = null; try { URL url = new URL(getCaptivePortalServerUrl(mContext)); // On networks with a PAC instead of fetching a URL that should result in a 204 @@ -699,6 +718,7 @@ public class NetworkMonitor extends StateMachine { long requestTimestamp = SystemClock.elapsedRealtime(); httpResponseCode = urlConnection.getResponseCode(); + redirectUrl = urlConnection.getHeaderField("location"); // Time how long it takes to get a response to our request long responseTimestamp = SystemClock.elapsedRealtime(); @@ -739,7 +759,7 @@ public class NetworkMonitor extends StateMachine { urlConnection.disconnect(); } } - return httpResponseCode; + return new CaptivePortalProbeResult(httpResponseCode, redirectUrl); } /** diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 6e7ea9925f91..03eb019bd3f8 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -77,7 +77,7 @@ public final class ContentService extends IContentService.Stub { static final boolean DEBUG = false; public static class Lifecycle extends SystemService { - private ContentService mContentService; + private ContentService mService; public Lifecycle(Context context) { super(context); @@ -87,14 +87,21 @@ public final class ContentService extends IContentService.Stub { public void onStart() { final boolean factoryTest = (FactoryTest .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL); - mContentService = new ContentService(getContext(), factoryTest); - publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mContentService); + mService = new ContentService(getContext(), factoryTest); + publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + mService.systemReady(); + } } @Override public void onCleanupUser(int userHandle) { - synchronized (mContentService.mCache) { - mContentService.mCache.remove(userHandle); + synchronized (mService.mCache) { + mService.mCache.remove(userHandle); } } } @@ -265,7 +272,7 @@ public final class ContentService extends IContentService.Stub { localeFilter, null, null); } - public void systemReady() { + void systemReady() { getSyncManager(); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index db41a54f1a0a..8af0af093ed7 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1402,24 +1402,12 @@ public class SyncManager { } } - private void restoreLostPeriodicSyncsIfNeeded(int userId) { - List<SyncOperation> periodicSyncs = new ArrayList<SyncOperation>(); - for (SyncOperation sync : getAllPendingSyncs()) { - if (sync.isPeriodic && sync.target.userId == userId) { - periodicSyncs.add(sync); - } - } - mSyncStorageEngine.restorePeriodicSyncsIfNeededForUser(userId, periodicSyncs); - } - private void onUserUnlocked(int userId) { // Make sure that accounts we're about to use are valid. AccountManagerService.getSingleton().validateAccounts(userId); mSyncAdapters.invalidateCache(userId); - restoreLostPeriodicSyncsIfNeeded(userId); - EndPoint target = new EndPoint(null, null, userId); updateRunningAccounts(target); diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index fb23265c2189..bc3fc6a47aef 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -826,35 +826,6 @@ public class SyncStorageEngine extends Handler { return true; } - /** - * STOPSHIP This is a temporary workaround and should be removed before shipping: b/28052438 - */ - void restorePeriodicSyncsIfNeededForUser(int userHandle, List<SyncOperation> periodicSyncs) { - if (mPeriodicSyncAddedListener == null) { - return; - } - synchronized (mAuthorities) { - for (int i = 0; i < mAuthorities.size(); i++) { - AuthorityInfo authority = mAuthorities.valueAt(i); - if (authority.target.userId == userHandle && authority.enabled) { - boolean periodicSyncAlreadyExists = false; - for (SyncOperation sync : periodicSyncs) { - if (authority.target.matchesSpec(sync.target)) { - periodicSyncAlreadyExists = true; - break; - } - } - // The periodic sync must have been lost due to previous bug. - if (!periodicSyncAlreadyExists) { - mPeriodicSyncAddedListener.onPeriodicSyncAdded(authority.target, - new Bundle(), DEFAULT_POLL_FREQUENCY_SECONDS, - calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)); - } - } - } - } - } - public void setMasterSyncAutomatically(boolean flag, int userId) { synchronized (mAuthorities) { Boolean auto = mMasterSyncAutomatically.get(userId); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index d80dc3b013d6..6b916be9d0fe 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -40,7 +40,6 @@ import android.location.IGnssStatusListener; import android.location.IGnssStatusProvider; import android.location.GnssMeasurementsEvent; import android.location.GnssNavigationMessage; -import android.location.GnssNavigationMessageEvent; import android.location.IGpsGeofenceHardware; import android.location.ILocationManager; import android.location.INetInitiatedListener; @@ -1668,16 +1667,6 @@ public class GnssLocationProvider implements LocationProviderInterface { } /** - * called from native code - GPS navigation message callback - */ - private void reportNavigationMessage(GnssNavigationMessageEvent event) { - if (event != null) { - mGnssNavigationMessageProvider - .onNavigationMessageAvailable(event.getNavigationMessage()); - } - } - - /** * called from native code to inform us what the GPS engine capabilities are */ private void setEngineCapabilities(int capabilities) { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 6d9fed46102b..c31d93e9fe1d 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -97,8 +97,6 @@ abstract public class ManagedServices { // List of packages in restored setting across all mUserProfiles, for quick // filtering upon package updates. private ArraySet<String> mRestoredPackages = new ArraySet<>(); - // State of current service categories - private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>(); // List of enabled packages that have nevertheless asked not to be run private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>(); @@ -342,47 +340,6 @@ abstract public class ManagedServices { } } - public void setCategoryState(String category, boolean enabled) { - synchronized (mMutex) { - final Boolean previous = mCategoryEnabled.put(category, enabled); - if (!(previous == null || previous != enabled)) { - return; - } - - // State changed - if (DEBUG) { - Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category); - } - - final int[] userIds = mUserProfiles.getCurrentProfileIds(); - for (int userId : userIds) { - final Set<ComponentName> componentNames = queryPackageForServices(null, - userId, category); - - // Disallow services not enabled in Settings - final ArraySet<ComponentName> userComponents = - loadComponentNamesFromSetting(mConfig.secureSettingName, userId); - if (userComponents == null) { - componentNames.clear(); - } else { - componentNames.retainAll(userComponents); - } - - if (DEBUG) { - Slog.d(TAG, "Components for category " + category + ": " + componentNames); - } - for (ComponentName c : componentNames) { - if (enabled) { - registerServiceLocked(c, userId); - } else { - unregisterServiceLocked(c, userId); - } - } - } - - } - } - private void rebuildRestoredPackages() { mRestoredPackages.clear(); mSnoozingForCurrentProfiles.clear(); @@ -454,20 +411,12 @@ abstract public class ManagedServices { } protected Set<ComponentName> queryPackageForServices(String packageName, int userId) { - return queryPackageForServices(packageName, userId, null); - } - - public Set<ComponentName> queryPackageForServices(String packageName, int userId, - String category) { Set<ComponentName> installed = new ArraySet<>(); final PackageManager pm = mContext.getPackageManager(); Intent queryIntent = new Intent(mConfig.serviceInterface); if (!TextUtils.isEmpty(packageName)) { queryIntent.setPackage(packageName); } - if (category != null) { - queryIntent.addCategory(category); - } List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( queryIntent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, @@ -578,15 +527,6 @@ abstract public class ManagedServices { } final Set<ComponentName> add = new HashSet<>(userComponents); - - // Remove components from disabled categories so that those services aren't run. - for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) { - if (!e.getValue()) { - Set<ComponentName> c = queryPackageForServices(null, userIds[i], - e.getKey()); - add.removeAll(c); - } - } add.removeAll(mSnoozingForCurrentProfiles); toAdd.put(userIds[i], add); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2765578a7c3d..2d3ca1f83b79 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1496,7 +1496,7 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification sbn = mNotificationList.get(i).sbn; if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId && (sbn.getNotification().flags - & Notification.FLAG_AUTOGROUP_SUMMARY) != 0) { + & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) { // We could pass back a cloneLight() but clients might get confused and // try to send this thing back to notify() again, which would not work // very well. @@ -2009,7 +2009,7 @@ public class NotificationManagerService extends SystemService { @Override public ComponentName getEffectsSuppressor() { enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor"); - return mEffectsSuppressors.get(0); + return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null; } @Override @@ -2543,18 +2543,13 @@ public class NotificationManagerService extends SystemService { // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); - boolean ignoreNotification = - removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid); - if (DBG) Slog.d(TAG, "ignoreNotification is " + ignoreNotification); // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; - if (ignoreNotification) { - enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; - } else if (old != null) { + if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, @@ -2562,10 +2557,6 @@ public class NotificationManagerService extends SystemService { enqueueStatus); } - if (ignoreNotification) { - return; - } - mRankingHelper.extractSignals(r); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); @@ -2681,58 +2672,6 @@ public class NotificationManagerService extends SystemService { } } - /** - * Performs group notification optimizations if SysUI is the only active - * notification listener and returns whether the given notification should - * be ignored. - * - * <p>Returns true if the given notification is a child of a group with a - * summary, which means that SysUI will never show it, and hence the new - * notification can be safely ignored. Also cancels any previous instance - * of the ignored notification.</p> - * - * <p>For summaries, cancels all children of that group, as SysUI will - * never show them anymore.</p> - * - * @return true if the given notification can be ignored as an optimization - */ - private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r, - NotificationRecord old, int callingUid, int callingPid) { - if (!ENABLE_CHILD_NOTIFICATIONS) { - // No optimizations are possible if listeners want groups. - if (mListeners.notificationGroupsDesired()) { - return false; - } - - StatusBarNotification sbn = r.sbn; - String group = sbn.getGroupKey(); - boolean isSummary = sbn.getNotification().isGroupSummary(); - boolean isChild = !isSummary && sbn.isGroup(); - - NotificationRecord summary = mSummaryByGroupKey.get(group); - if (isChild && summary != null) { - // Child with an active summary -> ignore - if (DBG) { - Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary " - + summary.getKey()); - } - // Make sure we don't leave an old version of the notification around. - if (old != null) { - if (DBG) { - Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey()); - } - cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION); - } - return true; - } else if (isSummary) { - // Summary -> cancel children - cancelGroupChildrenLocked(r, callingUid, callingPid, null, - REASON_GROUP_OPTIMIZATION); - } - } - return false; - } - @VisibleForTesting void buzzBeepBlinkLocked(NotificationRecord record) { boolean buzz = false; @@ -3851,7 +3790,7 @@ public class NotificationManagerService extends SystemService { return; } Set<ComponentName> rankerComponents = queryPackageForServices( - mRankerServicePackageName, UserHandle.USER_SYSTEM, null); + mRankerServicePackageName, UserHandle.USER_SYSTEM); Iterator<ComponentName> iterator = rankerComponents.iterator(); if (iterator.hasNext()) { ComponentName rankerComponent = iterator.next(); @@ -3869,7 +3808,6 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); - private boolean mNotificationGroupsDesired; public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); @@ -3902,7 +3840,6 @@ public class NotificationManagerService extends SystemService { final INotificationListener listener = (INotificationListener) info.service; final NotificationRankingUpdate update; synchronized (mNotificationList) { - updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); } try { @@ -3919,7 +3856,6 @@ public class NotificationManagerService extends SystemService { updateEffectsSuppressorLocked(); } mLightTrimListeners.remove(removed); - updateNotificationGroupsDesiredLocked(); } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { @@ -4112,31 +4048,6 @@ public class NotificationManagerService extends SystemService { } return false; } - - /** - * Returns whether any of the currently registered listeners wants to receive notification - * groups. - * - * <p>Currently we assume groups are desired by non-SystemUI listeners.</p> - */ - public boolean notificationGroupsDesired() { - return mNotificationGroupsDesired; - } - - private void updateNotificationGroupsDesiredLocked() { - mNotificationGroupsDesired = true; - // No listeners, no groups. - if (mServices.isEmpty()) { - mNotificationGroupsDesired = false; - return; - } - // One listener: Check whether it's SysUI. - if (mServices.size() == 1 && - mServices.get(0).component.getPackageName().equals("com.android.systemui")) { - mNotificationGroupsDesired = false; - return; - } - } } public static final class DumpFilter { diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 5ee7cc9ce3f3..43a0b9174f8e 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -294,7 +294,7 @@ public class LauncherAppsService extends SystemService { } @Override - public ResolveInfo resolveActivity(Intent intent, UserHandle user) + public ActivityInfo resolveActivity(ComponentName component, UserHandle user) throws RemoteException { ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user); if (!isUserEnabled(user)) { @@ -303,11 +303,11 @@ public class LauncherAppsService extends SystemService { long ident = Binder.clearCallingIdentity(); try { - ResolveInfo app = mPm.resolveActivityAsUser(intent, + IPackageManager pm = AppGlobals.getPackageManager(); + return pm.getActivityInfo(component, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, user.getIdentifier()); - return app; } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3b07fe185b4f..92b5996574be 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4922,6 +4922,7 @@ public class PackageManagerService extends IPackageManager.Stub { } ri = new ResolveInfo(mResolveInfo); ri.activityInfo = new ActivityInfo(ri.activityInfo); + ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); if (userId != 0) { @@ -16032,28 +16033,36 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void deleteApplicationCacheFiles(final String packageName, final IPackageDataObserver observer) { + final int userId = UserHandle.getCallingUserId(); + deleteApplicationCacheFilesAsUser(packageName, userId, observer); + } + + @Override + public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId, + final IPackageDataObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_CACHE_FILES, null); - // Queue up an async operation since the package deletion may take a little while. - final int userId = UserHandle.getCallingUserId(); + enforceCrossUserPermission(Binder.getCallingUid(), userId, + /* requireFullPermission= */ true, /* checkShell= */ false, + "delete application cache files"); final PackageParser.Package pkg; synchronized (mPackages) { pkg = mPackages.get(packageName); } + // Queue up an async operation since the package deletion may take a little while. mHandler.post(new Runnable() { public void run() { - try (PackageFreezer freezer = freezePackage(packageName, - "deleteApplicationCacheFiles")) { - synchronized (mInstallLock) { - final int flags = StorageManager.FLAG_STORAGE_DE - | StorageManager.FLAG_STORAGE_CE; - clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY); - clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - } - clearExternalStorageDataSync(packageName, userId, false); - } + synchronized (mInstallLock) { + final int flags = StorageManager.FLAG_STORAGE_DE + | StorageManager.FLAG_STORAGE_CE; + // We're only clearing cache files, so we don't care if the + // app is unfrozen and still able to run + clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY); + clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); + } + clearExternalStorageDataSync(packageName, userId, false); if (observer != null) { try { observer.onRemoveCompleted(packageName, true); @@ -16098,11 +16107,17 @@ public class PackageManagerService extends IPackageManager.Stub { mInstaller.getAppSize(ps.volumeUuid, packageName, userId, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE, ps.getCeDataInode(userId), ps.codePathString, stats); - return true; } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); return false; } + + // For now, ignore code size of packages on system partition + if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) { + stats.codeSize = 0; + } + + return true; } private int getUidTargetSdkVersionLockedLPr(int uid) { diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index aa10c084674c..a6350fe8cf35 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -92,7 +92,7 @@ public final class SELinuxMMAC { * MAC_PERMISSIONS class variable which is set at class load time which itself * is based on the USE_OVERRIDE_POLICY class variable. For further guidance on * the proper structure of a mac_permissions.xml file consult the source code - * located at external/sepolicy/mac_permissions.xml. + * located at system/sepolicy/mac_permissions.xml. * * @return boolean indicating if policy was correctly loaded. A value of false * typically indicates a structural problem with the xml or incorrectly @@ -373,7 +373,7 @@ public final class SELinuxMMAC { * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the * {@link PolicyBuilder} pattern class, where each instance is validated against a set * of invariants before being built and returned. Each instance can be guaranteed to - * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml + * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml * file. * <p> * The following is an example of how to use {@link Policy.PolicyBuilder} to create a @@ -519,7 +519,7 @@ final class Policy { * A nested builder class to create {@link Policy} instances. A {@link Policy} * class instance represents one valid policy stanza found in a mac_permissions.xml * file. A valid policy stanza is defined to be a signer stanza which obeys the rules - * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method + * outlined in system/sepolicy/mac_permissions.xml. The {@link #build} method * ensures a set of invariants are upheld enforcing the correct stanza structure * before returning a valid Policy object. */ diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 847f993ae959..7debf9b5b7fb 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2686,7 +2686,7 @@ final class Settings { void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws XmlPullParserException, java.io.IOException { - if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) { + if (bp.sourcePackage != null) { serializer.startTag(null, TAG_ITEM); serializer.attribute(null, ATTR_NAME, bp.name); serializer.attribute(null, "package", bp.sourcePackage); @@ -3348,8 +3348,12 @@ final class Settings { final String ptype = parser.getAttributeValue(null, "type"); if (name != null && sourcePackage != null) { final boolean dynamic = "dynamic".equals(ptype); - final BasePermission bp = new BasePermission(name.intern(), sourcePackage, - dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL); + BasePermission bp = out.get(name); + // If the permission is builtin, do not clobber it. + if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) { + bp = new BasePermission(name.intern(), sourcePackage, + dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL); + } bp.protectionLevel = readInt(parser, null, "protection", PermissionInfo.PROTECTION_NORMAL); bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 58559a53cb5a..b9b65ebc5ff8 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -28,6 +28,7 @@ import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -37,7 +38,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -51,6 +52,7 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String TAG_INTENT_EXTRAS = "intent-extras"; private static final String TAG_EXTRAS = "extras"; private static final String TAG_SHORTCUT = "shortcut"; + private static final String TAG_CATEGORIES = "categories"; private static final String ATTR_NAME = "name"; private static final String ATTR_DYNAMIC_COUNT = "dynamic-count"; @@ -67,6 +69,11 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_ICON_RES = "icon-res"; private static final String ATTR_BITMAP_PATH = "bitmap-path"; + private static final String NAME_CATEGORIES = "categories"; + + private static final String TAG_STRING_ARRAY_XMLUTILS = "string-array"; + private static final String ATTR_NAME_XMLUTILS = "name"; + /** * All the shortcuts from the package, keyed on IDs. */ @@ -305,7 +312,7 @@ class ShortcutPackage extends ShortcutPackageItem { * and return true. Otherwise just return false. */ public boolean tryApiCall(@NonNull ShortcutService s) { - if (getApiCallCount(s) >= s.mMaxDailyUpdates) { + if (getApiCallCount(s) >= s.mMaxUpdatesPerInterval) { return false; } mApiCallCount++; @@ -485,6 +492,16 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath()); } + { + final List<String> cat = si.getCategories(); + if (cat != null && cat.size() > 0) { + out.startTag(null, TAG_CATEGORIES); + XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]), + NAME_CATEGORIES, out); + out.endTag(null, TAG_CATEGORIES); + } + } + ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS, si.getIntentPersistableExtras()); ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); @@ -550,6 +567,7 @@ class ShortcutPackage extends ShortcutPackageItem { int flags; int iconRes; String bitmapPath; + String[] categories = null; id = ShortcutService.parseStringAttribute(parser, ATTR_ID); activityComponent = ShortcutService.parseComponentNameAttribute(parser, @@ -583,11 +601,21 @@ class ShortcutPackage extends ShortcutPackageItem { case TAG_EXTRAS: extras = PersistableBundle.restoreFromXml(parser); continue; + case TAG_CATEGORIES: + // This just contains string-array. + continue; + case TAG_STRING_ARRAY_XMLUTILS: + if (NAME_CATEGORIES.equals(ShortcutService.parseStringAttribute(parser, + ATTR_NAME_XMLUTILS))) { + categories = XmlUtils.readThisStringArrayXml(parser, TAG_STRING_ARRAY_XMLUTILS, null); + } + continue; } throw ShortcutService.throwForInvalidTag(depth, tag); } return new ShortcutInfo( - userId, id, packageName, activityComponent, /* icon =*/ null, title, text, intent, + userId, id, packageName, activityComponent, /* icon =*/ null, title, text, + (categories == null ? null : Arrays.asList(categories)), intent, intentPersistableExtras, weight, extras, lastChangedTimestamp, flags, iconRes, bitmapPath); } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 1641e1dce169..ac6510ae57ac 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -126,10 +126,10 @@ public class ShortcutService extends IShortcutService.Stub { static final boolean DEBUG_LOAD = false; // STOPSHIP if true @VisibleForTesting - static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day + static final long DEFAULT_RESET_INTERVAL_SEC = 60 * 60; // 1 hour @VisibleForTesting - static final int DEFAULT_MAX_DAILY_UPDATES = 10; + static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 2; @VisibleForTesting static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5; @@ -180,7 +180,7 @@ public class ShortcutService extends IShortcutService.Stub { /** * Key name for the max number of modifying API calls per app for every interval. (int) */ - String KEY_MAX_DAILY_UPDATES = "max_daily_updates"; + String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval"; /** * Key name for the max icon dimensions in DP, for non-low-memory devices. @@ -232,9 +232,9 @@ public class ShortcutService extends IShortcutService.Stub { private int mMaxDynamicShortcuts; /** - * Max number of updating API calls that each application can make a day. + * Max number of updating API calls that each application can make during the interval. */ - int mMaxDailyUpdates; + int mMaxUpdatesPerInterval; /** * Actual throttling-reset interval. By default it's a day. @@ -426,8 +426,8 @@ public class ShortcutService extends IShortcutService.Stub { ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC) * 1000L); - mMaxDailyUpdates = Math.max(0, (int) parser.getLong( - ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES)); + mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong( + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL)); mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP)); @@ -1319,10 +1319,13 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public boolean addDynamicShortcut(String packageName, ShortcutInfo newShortcut, + public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId) { verifyCaller(packageName, userId); + final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + final int size = newShortcuts.size(); + synchronized (mLock) { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); @@ -1330,12 +1333,15 @@ public class ShortcutService extends IShortcutService.Stub { if (!ps.tryApiCall(this)) { return false; } + for (int i = 0; i < size; i++) { + final ShortcutInfo newShortcut = newShortcuts.get(i); - // Validate the shortcut. - fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); + // Validate the shortcut. + fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); - // Add it. - ps.addDynamicShortcut(this, newShortcut); + // Add it. + ps.addDynamicShortcut(this, newShortcut); + } } userPackageChanged(packageName, userId); @@ -1343,19 +1349,22 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public void deleteDynamicShortcut(String packageName, String shortcutId, + public void removeDynamicShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) { verifyCaller(packageName, userId); - Preconditions.checkStringNotEmpty(shortcutId, "shortcutId must be provided"); + Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); synchronized (mLock) { - getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, shortcutId); + for (int i = shortcutIds.size() - 1; i >= 0; i--) { + getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, + Preconditions.checkStringNotEmpty((String) shortcutIds.get(i))); + } } userPackageChanged(packageName, userId); } @Override - public void deleteAllDynamicShortcuts(String packageName, @UserIdInt int userId) { + public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) { verifyCaller(packageName, userId); synchronized (mLock) { @@ -1409,7 +1418,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); synchronized (mLock) { - return mMaxDailyUpdates + return mMaxUpdatesPerInterval - getPackageShortcutsLocked(packageName, userId).getApiCallCount(this); } } @@ -2079,8 +2088,8 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(mSaveDelayMillis); pw.print(" resetInterval:"); pw.println(mResetInterval); - pw.print(" maxDailyUpdates:"); - pw.println(mMaxDailyUpdates); + pw.print(" maxUpdatesPerInterval:"); + pw.println(mMaxUpdatesPerInterval); pw.print(" maxDynamicShortcuts:"); pw.println(mMaxDynamicShortcuts); pw.println(); @@ -2423,8 +2432,8 @@ public class ShortcutService extends IShortcutService.Stub { } @VisibleForTesting - int getMaxDailyUpdatesForTest() { - return mMaxDailyUpdates; + int getMaxUpdatesPerIntervalForTest() { + return mMaxUpdatesPerInterval; } @VisibleForTesting diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java index 160d44c58bc9..27077f2f74f7 100644 --- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java @@ -27,8 +27,11 @@ import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; +import android.service.vr.IVrManager; import android.util.DisplayMetrics; import android.util.Slog; import android.util.SparseBooleanArray; @@ -45,6 +48,7 @@ import android.widget.Button; import android.widget.FrameLayout; import com.android.internal.R; +import com.android.server.vr.VrManagerService; /** * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden @@ -66,6 +70,7 @@ public class ImmersiveModeConfirmation { private long mPanicTime; private WindowManager mWindowManager; private int mCurrentUserId; + private IVrManager mVrManager; public ImmersiveModeConfirmation(Context context) { mContext = context; @@ -75,6 +80,8 @@ public class ImmersiveModeConfirmation { .getInteger(R.integer.config_immersive_mode_confirmation_panic); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + mVrManager = (IVrManager) IVrManager.Stub.asInterface( + ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE)); } private long getNavBarExitDuration() { @@ -112,6 +119,14 @@ public class ImmersiveModeConfirmation { } } + private boolean getVrMode() { + boolean vrMode = false; + try { + vrMode = mVrManager.getVrModeState(); + } catch (RemoteException ex) { } + return vrMode; + } + public void immersiveModeChanged(String pkg, boolean isImmersiveMode, boolean userSetupComplete) { mHandler.removeMessages(H.SHOW); @@ -119,7 +134,10 @@ public class ImmersiveModeConfirmation { final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg); if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s", disabled, mConfirmed)); - if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) { + if (!disabled + && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) + && userSetupComplete + && !getVrMode()) { mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); } } else { diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index f004b4592413..49ff385ee27f 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -50,6 +50,8 @@ import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeLis import com.android.server.utils.ManagedApplicationService; import com.android.server.utils.ManagedApplicationService.BinderChecker; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.lang.StringBuilder; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -103,6 +105,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC new RemoteCallbackList<>(); private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>(); private String mPreviousNotificationPolicyAccessPackage; + private String mPreviousCoarseLocationPackage; private String mPreviousManageOverlayPackage; private static final int MSG_VR_STATE_CHANGE = 0; @@ -186,6 +189,32 @@ public class VrManagerService extends SystemService implements EnabledComponentC return VrManagerService.this.getVrMode(); } + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("permission denied: can't dump VrManagerService from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + pw.print("mVrModeEnabled="); + pw.println(mVrModeEnabled); + pw.print("mCurrentVrModeUser="); + pw.println(mCurrentVrModeUser); + pw.print("mRemoteCallbacks="); + int i=mRemoteCallbacks.beginBroadcast(); // create the broadcast item array + while(i-->0) { + pw.print(mRemoteCallbacks.getBroadcastItem(i)); + if (i>0) pw.print(", "); + } + mRemoteCallbacks.finishBroadcast(); + pw.println(); + pw.print("mCurrentVrService="); + pw.println(mCurrentVrService != null ? mCurrentVrService.getComponent() : "(none)"); + pw.print("mCurrentVrModeComponent="); + pw.println(mCurrentVrModeComponent); + } + }; private void enforceCallerPermission(String permission) { @@ -418,6 +447,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC mWasDefaultGranted = true; + grantCoarseLocationAccess(pName, userId); grantOverlayAccess(pName, userId); grantNotificationPolicyAccess(pName); grantNotificationListenerAccess(pName, userId); @@ -447,6 +477,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC String pName = component.getPackageName(); if (mWasDefaultGranted) { + revokeCoarseLocationAccess(userId); revokeOverlayAccess(userId); revokeNotificationPolicyAccess(pName); revokeNotificiationListenerAccess(); @@ -455,6 +486,27 @@ public class VrManagerService extends SystemService implements EnabledComponentC } + private void grantCoarseLocationAccess(String pkg, UserHandle userId) { + PackageManager pm = mContext.getPackageManager(); + boolean prev = (PackageManager.PERMISSION_GRANTED == + pm.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, pkg)); + mPreviousCoarseLocationPackage = null; + if (!prev) { + pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION, + userId); + mPreviousCoarseLocationPackage = pkg; + } + } + + private void revokeCoarseLocationAccess(UserHandle userId) { + PackageManager pm = mContext.getPackageManager(); + if (mPreviousCoarseLocationPackage != null) { + pm.revokeRuntimePermission(mPreviousCoarseLocationPackage, + android.Manifest.permission.ACCESS_COARSE_LOCATION, userId); + mPreviousCoarseLocationPackage = null; + } + } + private void grantOverlayAccess(String pkg, UserHandle userId) { PackageManager pm = mContext.getPackageManager(); boolean prev = (PackageManager.PERMISSION_GRANTED == @@ -476,7 +528,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } - private void grantNotificationPolicyAccess(String pkg) { NotificationManager nm = mContext.getSystemService(NotificationManager.class); boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index fe3210491b90..ca1a7ac80259 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -16,9 +16,12 @@ package com.android.server.wallpaper; -import static android.app.WallpaperManager.FLAG_SYSTEM; import static android.app.WallpaperManager.FLAG_LOCK; -import static android.os.ParcelFileDescriptor.*; +import static android.app.WallpaperManager.FLAG_SYSTEM; +import static android.os.ParcelFileDescriptor.MODE_CREATE; +import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; +import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; +import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; import android.app.ActivityManager; import android.app.ActivityManagerNative; @@ -41,27 +44,26 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; -import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Environment; +import android.os.FileObserver; import android.os.FileUtils; import android.os.IBinder; import android.os.IRemoteCallback; -import android.os.RemoteException; -import android.os.FileObserver; import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; +import android.os.RemoteException; import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; @@ -79,35 +81,62 @@ import android.view.Display; import android.view.IWindowManager; import android.view.WindowManager; +import com.android.internal.R; +import com.android.internal.content.PackageMonitor; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.JournaledFile; +import com.android.server.EventLogTags; +import com.android.server.SystemService; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.BufferedOutputStream; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; import java.io.File; -import java.io.FileNotFoundException; +import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import com.android.internal.content.PackageMonitor; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.JournaledFile; -import com.android.internal.R; -import com.android.server.EventLogTags; - -import libcore.io.IoUtils; - public class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperManagerService"; static final boolean DEBUG = false; + public static class Lifecycle extends SystemService { + private WallpaperManagerService mService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new WallpaperManagerService(getContext()); + publishBinderService(Context.WALLPAPER_SERVICE, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + mService.systemReady(); + } + } + + @Override + public void onUnlockUser(int userHandle) { + mService.onUnlockUser(userHandle); + } + } + final Object mLock = new Object(); /** @@ -417,6 +446,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final AppOpsManager mAppOpsManager; WallpaperData mLastWallpaper; IWallpaperManagerCallback mKeyguardListener; + boolean mWaitingForUnlock; /** * ID of the current wallpaper, changed every time anything sets a wallpaper. @@ -744,8 +774,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (wallpaper.wallpaperComponent != null && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) { try { - mContext.getPackageManager().getServiceInfo( - wallpaper.wallpaperComponent, 0); + mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } catch (NameNotFoundException e) { Slog.w(TAG, "Wallpaper component gone, removing: " + wallpaper.wallpaperComponent); @@ -755,8 +786,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (wallpaper.nextWallpaperComponent != null && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) { try { - mContext.getPackageManager().getServiceInfo( - wallpaper.nextWallpaperComponent, 0); + mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } catch (NameNotFoundException e) { wallpaper.nextWallpaperComponent = null; } @@ -793,7 +825,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } - public void systemRunning() { + void systemReady() { if (DEBUG) Slog.v(TAG, "systemReady"); WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); // If we think we're going to be using the system image wallpaper imagery, make @@ -828,7 +860,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); + final String action = intent.getAction(); if (Intent.ACTION_USER_REMOVED.equals(action)) { onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); @@ -892,6 +924,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mLockWallpaperMap.remove(userId); } + void onUnlockUser(int userId) { + synchronized (mLock) { + if (mCurrentUserId == userId && mWaitingForUnlock) { + switchUser(userId, null); + } + } + } + void onRemoveUser(int userId) { if (userId < 1) return; @@ -919,18 +959,34 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) { synchronized (mLock) { - RuntimeException e = null; - try { - ComponentName cname = wallpaper.wallpaperComponent != null ? - wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent; - if (bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { - return; + mWaitingForUnlock = false; + final ComponentName cname = wallpaper.wallpaperComponent != null ? + wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent; + if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { + // We failed to bind the desired wallpaper, but that might + // happen if the wallpaper isn't direct-boot aware + ServiceInfo si = null; + try { + si = mIPackageManager.getServiceInfo(cname, + PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); + } catch (RemoteException ignored) { + } + + if (si == null) { + Slog.w(TAG, "Failure starting previous wallpaper; clearing"); + clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply); + } else { + Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked"); + // We might end up persisting the current wallpaper data + // while locked, so pretend like the component was actually + // bound into place + wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent; + final WallpaperData fallback = new WallpaperData(wallpaper.userId, + WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); + bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); + mWaitingForUnlock = true; } - } catch (RuntimeException e1) { - e = e1; } - Slog.w(TAG, "Failure starting previous wallpaper", e); - clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply); } } diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index ed935ced0037..a5d68dabbdeb 100644 --- a/services/core/java/com/android/server/webkit/SystemImpl.java +++ b/services/core/java/com/android/server/webkit/SystemImpl.java @@ -34,7 +34,6 @@ import android.provider.Settings.Global; import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.Log; -import android.webkit.WebViewFactory.MissingWebViewPackageException; import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; @@ -68,6 +67,7 @@ public class SystemImpl implements SystemInterface { @Override public WebViewProviderInfo[] getWebViewPackages() { int numFallbackPackages = 0; + int numAvailableByDefaultPackages = 0; XmlResourceParser parser = null; List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>(); try { @@ -83,12 +83,12 @@ public class SystemImpl implements SystemInterface { if (element.equals(TAG_WEBVIEW_PROVIDER)) { String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME); if (packageName == null) { - throw new MissingWebViewPackageException( + throw new AndroidRuntimeException( "WebView provider in framework resources missing package name"); } String description = parser.getAttributeValue(null, TAG_DESCRIPTION); if (description == null) { - throw new MissingWebViewPackageException( + throw new AndroidRuntimeException( "WebView provider in framework resources missing description"); } boolean availableByDefault = "true".equals( @@ -100,22 +100,33 @@ public class SystemImpl implements SystemInterface { readSignatures(parser)); if (currentProvider.isFallback) { numFallbackPackages++; + if (!currentProvider.availableByDefault) { + throw new AndroidRuntimeException( + "Each WebView fallback package must be available by default."); + } if (numFallbackPackages > 1) { throw new AndroidRuntimeException( - "There can be at most one webview fallback package."); + "There can be at most one WebView fallback package."); } } + if (currentProvider.availableByDefault) { + numAvailableByDefaultPackages++; + } webViewProviders.add(currentProvider); } else { - Log.e(TAG, "Found an element that is not a webview provider"); + Log.e(TAG, "Found an element that is not a WebView provider"); } } } catch (XmlPullParserException | IOException e) { - throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e); + throw new AndroidRuntimeException("Error when parsing WebView config " + e); } finally { if (parser != null) parser.close(); } + if (numAvailableByDefaultPackages == 0) { + throw new AndroidRuntimeException("There must be at least one WebView package " + + "that is available by default"); + } return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]); } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java index 487bc0f4f9ed..e17ea49bc3a3 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java @@ -119,6 +119,8 @@ public class WebViewUpdateServiceImpl { } private void updateFallbackStateOnBoot() { + if (!mSystemInterface.isFallbackLogicEnabled()) return; + WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages(); updateFallbackState(webviewProviders, true); } @@ -505,8 +507,15 @@ public class WebViewUpdateServiceImpl { mWebViewPackageDirty = false; // If we have changed provider since we started the relro creation we need to // redo the whole process using the new package instead. - PackageInfo newPackage = findPreferredWebViewPackage(); - onWebViewProviderChanged(newPackage); + try { + PackageInfo newPackage = findPreferredWebViewPackage(); + onWebViewProviderChanged(newPackage); + } catch (WebViewFactory.MissingWebViewPackageException e) { + // If we can't find any valid WebView package we are now in a state where + // mAnyWebViewInstalled is false, so loading WebView will be blocked and we + // should simply wait until we receive an intent declaring a new package was + // installed. + } } else { mLock.notifyAll(); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 28379f491318..1f1648116b9d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -290,7 +290,7 @@ class DisplayContent { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { TaskStack stack = mStacks.get(stackNdx); stack.getBounds(mTmpRect); - if (!mTmpRect.contains(x, y)) { + if (!mTmpRect.contains(x, y) || stack.isAdjustedForMinimizedDockedStack()) { continue; } final ArrayList<Task> tasks = stack.getTasks(); diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 6ac71c795ca7..ff537bef1aa9 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -270,6 +270,19 @@ public class DockedStackDividerController implements DimLayerUser { mDockedStackListeners.finishBroadcast(); } + void notifyDockSideChanged(int newDockSide) { + final int size = mDockedStackListeners.beginBroadcast(); + for (int i = 0; i < size; ++i) { + final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); + try { + listener.onDockSideChanged(newDockSide); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering dock side changed event.", e); + } + } + mDockedStackListeners.finishBroadcast(); + } + void registerDockedStackListener(IDockedStackListener listener) { mDockedStackListeners.register(listener); notifyDockedDividerVisibilityChanged(wasVisible()); diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index eea0e73c1b0b..be9fb26bb286 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -294,7 +294,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { final WindowState child = windows.get(winNdx); final InputChannel inputChannel = child.mInputChannel; final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; - if (inputChannel == null || inputWindowHandle == null || child.mRemoved) { + if (inputChannel == null || inputWindowHandle == null || child.mRemoved + || child.isAdjustedForMinimizedDock()) { // Skip this window because it cannot possibly receive input. continue; } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 446b74bc1933..7074a83a812f 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -16,6 +16,20 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.view.WindowManager.DOCKED_BOTTOM; +import static android.view.WindowManager.DOCKED_INVALID; +import static android.view.WindowManager.DOCKED_LEFT; +import static android.view.WindowManager.DOCKED_RIGHT; +import static android.view.WindowManager.DOCKED_TOP; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; + import android.app.ActivityManager.StackId; import android.content.res.Configuration; import android.graphics.Rect; @@ -35,20 +49,6 @@ import com.android.server.EventLogTags; import java.io.PrintWriter; import java.util.ArrayList; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; -import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - public class TaskStack implements DimLayer.DimLayerUser, BoundsAnimationController.AnimateBoundsUser { @@ -379,10 +379,15 @@ public class TaskStack implements DimLayer.DimLayerUser, return false; } + final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID; mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (mStackId == DOCKED_STACK_ID) { repositionDockedStackAfterRotation(mTmpRect2); snapDockedStackAfterRotation(mTmpRect2); + final int newDockSide = getDockSide(mTmpRect2); + if (oldDockSide != newDockSide) { + mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); + } } if (scheduleResize) { @@ -910,7 +915,7 @@ public class TaskStack implements DimLayer.DimLayerUser, // Calculate the content bounds excluding the area occupied by IME getDisplayContent().getContentRect(displayContentRect); contentBounds.set(displayContentRect); - int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top); + int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); // if IME window is animating, get its actual vertical shown position (but no smaller than // the final target vertical position) diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c991130b55e7..c48d7d11692e 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -774,10 +774,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame); - // Offset the actual frame by the amount layout frame is off. - mFrame.offset(-layoutXDiff, -layoutYDiff); - mCompatFrame.offset(-layoutXDiff, -layoutYDiff); - // Calculate the outsets before the content frame gets shrinked to the window frame. if (hasOutsets) { mOutsets.set(Math.max(mContentFrame.left - mOutsetFrame.left, 0), @@ -816,20 +812,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { mMovedByResize = true; } } else { - mContentFrame.set(Math.max(mContentFrame.left, layoutContainingFrame.left), - Math.max(mContentFrame.top, layoutContainingFrame.top), - Math.min(mContentFrame.right, layoutContainingFrame.right), - Math.min(mContentFrame.bottom, layoutContainingFrame.bottom)); + mContentFrame.set(Math.max(mContentFrame.left, mFrame.left), + Math.max(mContentFrame.top, mFrame.top), + Math.min(mContentFrame.right, mFrame.right), + Math.min(mContentFrame.bottom, mFrame.bottom)); - mVisibleFrame.set(Math.max(mVisibleFrame.left, layoutContainingFrame.left), - Math.max(mVisibleFrame.top, layoutContainingFrame.top), - Math.min(mVisibleFrame.right, layoutContainingFrame.right), - Math.min(mVisibleFrame.bottom, layoutContainingFrame.bottom)); + mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left), + Math.max(mVisibleFrame.top, mFrame.top), + Math.min(mVisibleFrame.right, mFrame.right), + Math.min(mVisibleFrame.bottom, mFrame.bottom)); - mStableFrame.set(Math.max(mStableFrame.left, layoutContainingFrame.left), - Math.max(mStableFrame.top, layoutContainingFrame.top), - Math.min(mStableFrame.right, layoutContainingFrame.right), - Math.min(mStableFrame.bottom, layoutContainingFrame.bottom)); + mStableFrame.set(Math.max(mStableFrame.left, mFrame.left), + Math.max(mStableFrame.top, mFrame.top), + Math.min(mStableFrame.right, mFrame.right), + Math.min(mStableFrame.bottom, mFrame.bottom)); } if (fullscreenTask && !windowsAreFloating) { @@ -857,30 +853,33 @@ final class WindowState implements WindowManagerPolicy.WindowState { getDisplayContent().getLogicalDisplayRect(mTmpRect); // Override right and/or bottom insets in case if the frame doesn't fit the screen in // non-fullscreen mode. - boolean overrideRightInset = !fullscreenTask && layoutContainingFrame.right > mTmpRect.right; - boolean overrideBottomInset = !fullscreenTask && layoutContainingFrame.bottom > mTmpRect.bottom; - mContentInsets.set(mContentFrame.left - layoutContainingFrame.left, - mContentFrame.top - layoutContainingFrame.top, + boolean overrideRightInset = !fullscreenTask && mFrame.right > mTmpRect.right; + boolean overrideBottomInset = !fullscreenTask && mFrame.bottom > mTmpRect.bottom; + mContentInsets.set(mContentFrame.left - mFrame.left, + mContentFrame.top - mFrame.top, overrideRightInset ? mTmpRect.right - mContentFrame.right - : layoutContainingFrame.right - mContentFrame.right, + : mFrame.right - mContentFrame.right, overrideBottomInset ? mTmpRect.bottom - mContentFrame.bottom - : layoutContainingFrame.bottom - mContentFrame.bottom); + : mFrame.bottom - mContentFrame.bottom); - mVisibleInsets.set(mVisibleFrame.left - layoutContainingFrame.left, - mVisibleFrame.top - layoutContainingFrame.top, + mVisibleInsets.set(mVisibleFrame.left - mFrame.left, + mVisibleFrame.top - mFrame.top, overrideRightInset ? mTmpRect.right - mVisibleFrame.right - : layoutContainingFrame.right - mVisibleFrame.right, + : mFrame.right - mVisibleFrame.right, overrideBottomInset ? mTmpRect.bottom - mVisibleFrame.bottom - : layoutContainingFrame.bottom - mVisibleFrame.bottom); + : mFrame.bottom - mVisibleFrame.bottom); - mStableInsets.set(Math.max(mStableFrame.left - layoutContainingFrame.left, 0), - Math.max(mStableFrame.top - layoutContainingFrame.top, 0), + mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0), + Math.max(mStableFrame.top - mFrame.top, 0), overrideRightInset ? Math.max(mTmpRect.right - mStableFrame.right, 0) - : Math.max(layoutContainingFrame.right - mStableFrame.right, 0), + : Math.max(mFrame.right - mStableFrame.right, 0), overrideBottomInset ? Math.max(mTmpRect.bottom - mStableFrame.bottom, 0) - : Math.max(layoutContainingFrame.bottom - mStableFrame.bottom, 0)); + : Math.max(mFrame.bottom - mStableFrame.bottom, 0)); } + // Offset the actual frame by the amount layout frame is off. + mFrame.offset(-layoutXDiff, -layoutYDiff); + mCompatFrame.offset(-layoutXDiff, -layoutYDiff); mContentFrame.offset(-layoutXDiff, -layoutYDiff); mVisibleFrame.offset(-layoutXDiff, -layoutYDiff); mStableFrame.offset(-layoutXDiff, -layoutYDiff); @@ -1390,6 +1389,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { return configChanged; } + boolean isAdjustedForMinimizedDock() { + return mAppToken != null && mAppToken.mTask != null + && mAppToken.mTask.mStack.isAdjustedForMinimizedDock(); + } + void removeLocked() { disposeInputChannel(); @@ -1776,7 +1780,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { return isVisibleOrAdding() && (mViewVisibility == View.VISIBLE) && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0) - && (mAppToken == null || mAppToken.windowsAreFocusable()); + && (mAppToken == null || mAppToken.windowsAreFocusable()) + && !isAdjustedForMinimizedDock(); } @Override diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 9c25f63dfa2a..140f3811ef53 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1288,7 +1288,7 @@ class WindowStateAnimator { } final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw(); - if (w == winShowWhenLocked) { + if (w == winShowWhenLocked && mPolicy.isKeyguardShowingOrOccluded()) { return; } diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 78b0844e8ed4..93eb82fd9794 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -562,7 +562,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, method_reportNavigationMessages = env->GetMethodID( clazz, "reportNavigationMessage", - "(Landroid/location/GnssNavigationMessageEvent;)V"); + "(Landroid/location/GnssNavigationMessage;)V"); err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { @@ -1486,26 +1486,6 @@ static jobject translate_gnss_navigation_message( return object.get(); } -static void set_navigation_message(jobject navigationMessage) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jclass navigationMessageEventClass = - env->FindClass("android/location/GnssNavigationMessageEvent"); - jmethodID navigationMessageEventCtor = env->GetMethodID( - navigationMessageEventClass, - "<init>", - "(Landroid/location/GnssNavigationMessage;)V"); - jobject navigationMessageEvent = env->NewObject( - navigationMessageEventClass, - navigationMessageEventCtor, - navigationMessage); - env->CallVoidMethod(mCallbacksObj, - method_reportNavigationMessages, - navigationMessageEvent); - checkAndClearExceptionFromCallback(env, __FUNCTION__); - env->DeleteLocalRef(navigationMessageEventClass); - env->DeleteLocalRef(navigationMessageEvent); -} - static void navigation_message_callback(GpsNavigationMessage* message) { if (message == NULL) { ALOGE("Invalid Navigation Message provided to callback"); @@ -1517,7 +1497,9 @@ static void navigation_message_callback(GpsNavigationMessage* message) { } JNIEnv* env = AndroidRuntime::getJNIEnv(); jobject navigationMessage = translate_gps_navigation_message(env, message); - set_navigation_message(navigationMessage); + env->CallVoidMethod(mCallbacksObj, + method_reportNavigationMessages, + navigationMessage); env->DeleteLocalRef(navigationMessage); } @@ -1532,7 +1514,9 @@ static void gnss_navigation_message_callback(GnssNavigationMessage* message) { } JNIEnv* env = AndroidRuntime::getJNIEnv(); jobject navigationMessage = translate_gnss_navigation_message(env, message); - set_navigation_message(navigationMessage); + env->CallVoidMethod(mCallbacksObj, + method_reportNavigationMessages, + navigationMessage); env->DeleteLocalRef(navigationMessage); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d2296331bce0..0454b0052d48 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -211,7 +211,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; - private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning; + private static final int MONITORING_CERT_NOTIFICATION_ID = R.plurals.ssl_ca_cert_warning; private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001; private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; @@ -2696,23 +2696,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Build and show a warning notification int smallIconId; String contentText; - // TODO Why does it use the DO name? The cert APIs are all for PO. b/25772443 - final String ownerName = getDeviceOwnerName(); - if (isManagedProfile(userHandle.getIdentifier())) { - contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_administrator); + if (getProfileOwner(userHandle.getIdentifier()) != null) { + contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed, + getProfileOwnerName(userHandle.getIdentifier())); smallIconId = R.drawable.stat_sys_certificate_info; - } else if (ownerName != null) { - contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed, ownerName); + } else if (getDeviceOwnerUserId() == userHandle.getIdentifier()) { + contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed, + getDeviceOwnerName()); smallIconId = R.drawable.stat_sys_certificate_info; } else { contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown); smallIconId = android.R.drawable.stat_sys_warning; } + final int numberOfCertificates = pendingCertificates.size(); Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO); dialogIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); dialogIntent.setPackage("com.android.settings"); + dialogIntent.putExtra(Settings.EXTRA_NUMBER_OF_CERTIFICATES, numberOfCertificates); PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null, userHandle); @@ -2726,7 +2728,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final Notification noti = new Notification.Builder(userContext) .setSmallIcon(smallIconId) - .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning)) + .setContentTitle(mContext.getResources().getQuantityText( + R.plurals.ssl_ca_cert_warning, numberOfCertificates)) .setContentText(contentText) .setContentIntent(notifyIntent) .setPriority(Notification.PRIORITY_HIGH) @@ -8657,7 +8660,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setOrganizationName(@NonNull ComponentName who, String text) { + public void setOrganizationName(@NonNull ComponentName who, CharSequence text) { if (!mHasFeature) { return; } @@ -8668,14 +8671,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (!TextUtils.equals(admin.organizationName, text)) { - admin.organizationName = TextUtils.nullIfEmpty(text); + admin.organizationName = (text == null || text.length() == 0) + ? null : text.toString(); saveSettingsLocked(userHandle); } } } @Override - public String getOrganizationName(@NonNull ComponentName who) { + public CharSequence getOrganizationName(@NonNull ComponentName who) { if (!mHasFeature) { return null; } @@ -8689,7 +8693,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public String getOrganizationNameForUser(int userHandle) { + public CharSequence getOrganizationNameForUser(int userHandle) { if (!mHasFeature) { return null; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e7ae2b0fcfd5..8c2f559677c4 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -18,7 +18,6 @@ package com.android.server; import android.app.ActivityManagerNative; import android.app.ActivityThread; -import android.app.IAlarmManager; import android.app.INotificationManager; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; @@ -55,13 +54,11 @@ import com.android.internal.os.SamplingProfilerIntegration; import com.android.internal.os.ZygoteInit; import com.android.internal.widget.ILockSettings; import com.android.server.accessibility.AccessibilityManagerService; -import com.android.server.accounts.AccountManagerService; import com.android.server.am.ActivityManagerService; import com.android.server.audio.AudioService; import com.android.server.camera.CameraService; import com.android.server.clipboard.ClipboardService; import com.android.server.connectivity.MetricsLoggerService; -import com.android.server.content.ContentService; import com.android.server.devicepolicy.DevicePolicyManagerService; import com.android.server.display.DisplayManagerService; import com.android.server.dreams.DreamManagerService; @@ -97,7 +94,6 @@ import com.android.server.tv.TvInputManagerService; import com.android.server.twilight.TwilightService; import com.android.server.usage.UsageStatsService; import com.android.server.vr.VrManagerService; -import com.android.server.wallpaper.WallpaperManagerService; import com.android.server.webkit.WebViewUpdateService; import com.android.server.wm.WindowManagerService; @@ -157,8 +153,12 @@ public final class SystemServer { "com.google.android.clockwork.ThermalObserver"; private static final String WEAR_BLUETOOTH_SERVICE_CLASS = "com.google.android.clockwork.bluetooth.WearBluetoothService"; + private static final String ACCOUNT_SERVICE_CLASS = + "com.android.server.accounts.AccountManagerService$Lifecycle"; private static final String CONTENT_SERVICE_CLASS = "com.android.server.content.ContentService$Lifecycle"; + private static final String WALLPAPER_SERVICE_CLASS = + "com.android.server.wallpaper.WallpaperManagerService$Lifecycle"; private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; @@ -187,6 +187,7 @@ public final class SystemServer { private PackageManagerService mPackageManagerService; private PackageManager mPackageManager; private ContentResolver mContentResolver; + private EntropyMixer mEntropyMixer; private boolean mOnlyCore; private boolean mFirstBoot; @@ -497,10 +498,7 @@ public final class SystemServer { */ private void startOtherServices() { final Context context = mSystemContext; - AccountManagerService accountManager = null; - ContentService contentService = null; VibratorService vibrator = null; - IAlarmManager alarm = null; IMountService mountService = null; NetworkManagementService networkManagement = null; NetworkStatsService networkStats = null; @@ -516,8 +514,6 @@ public final class SystemServer { TelephonyRegistry telephonyRegistry = null; ConsumerIrService consumerIr = null; MmsServiceBroker mmsService = null; - EntropyMixer entropyMixer = null; - VrManagerService vrManagerService = null; HardwarePropertiesManagerService hardwarePropertiesService = null; boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false); @@ -556,7 +552,7 @@ public final class SystemServer { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); traceBeginAndSlog("StartEntropyMixer"); - entropyMixer = new EntropyMixer(context); + mEntropyMixer = new EntropyMixer(context); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); mContentResolver = context.getContentResolver(); @@ -566,13 +562,7 @@ public final class SystemServer { // The AccountManager must come before the ContentService traceBeginAndSlog("StartAccountManagerService"); - try { - // TODO: seems like this should be disable-able, but req'd by ContentService - accountManager = new AccountManagerService(context); - ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager); - } catch (Throwable e) { - Slog.e(TAG, "Failure starting Account Manager", e); - } + mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); traceBeginAndSlog("StartContentService"); @@ -593,9 +583,9 @@ public final class SystemServer { ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + traceBeginAndSlog("StartAlarmManagerService"); mSystemServiceManager.startService(AlarmManagerService.class); - alarm = IAlarmManager.Stub.asInterface( - ServiceManager.getService(Context.ALARM_SERVICE)); + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); traceBeginAndSlog("InitWatchdog"); final Watchdog watchdog = Watchdog.getInstance(); @@ -652,7 +642,6 @@ public final class SystemServer { StatusBarManagerService statusBar = null; INotificationManager notification = null; - WallpaperManagerService wallpaper = null; LocationManagerService location = null; CountryDetectorService countryDetector = null; ILockSettings lockSettings = null; @@ -823,7 +812,7 @@ public final class SystemServer { mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS); mSystemServiceManager.startService(WIFI_SERVICE_CLASS); mSystemServiceManager.startService( - "com.android.server.wifi.WifiScanningService"); + "com.android.server.wifi.scanner.WifiScanningService"); if (!disableRtt) { mSystemServiceManager.startService("com.android.server.wifi.RttService"); @@ -886,24 +875,6 @@ public final class SystemServer { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAccountManagerServiceReady"); - try { - if (accountManager != null) - accountManager.systemReady(); - } catch (Throwable e) { - reportWtf("making Account Manager Service ready", e); - } - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeContentServiceReady"); - try { - if (contentService != null) - contentService.systemReady(); - } catch (Throwable e) { - reportWtf("making Content Service ready", e); - } - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - mSystemServiceManager.startService(NotificationManagerService.class); notification = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); @@ -946,12 +917,7 @@ public final class SystemServer { if (!disableNonCoreServices && context.getResources().getBoolean( R.bool.config_enableWallpaperService)) { traceBeginAndSlog("StartWallpaperManagerService"); - try { - wallpaper = new WallpaperManagerService(context); - ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); - } catch (Throwable e) { - reportWtf("starting Wallpaper Service", e); - } + mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } @@ -1278,12 +1244,10 @@ public final class SystemServer { final NetworkPolicyManagerService networkPolicyF = networkPolicy; final ConnectivityService connectivityF = connectivity; final NetworkScoreService networkScoreF = networkScore; - final WallpaperManagerService wallpaperF = wallpaper; final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService; - final StatusBarManagerService statusBarF = statusBar; final AssetAtlasService atlasF = atlas; final InputManagerService inputManagerF = inputManager; final TelephonyRegistry telephonyRegistryF = telephonyRegistry; @@ -1371,11 +1335,6 @@ public final class SystemServer { SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); try { - if (wallpaperF != null) wallpaperF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying WallpaperService running", e); - } - try { if (locationF != null) locationF.systemRunning(); } catch (Throwable e) { reportWtf("Notifying Location Service running", e); diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index 54aeb3db7319..b6ad25b147a2 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -355,6 +355,8 @@ public class IpManager extends StateMachine { public void startProvisioning(ProvisioningConfiguration req) { getNetworkInterface(); + + mCallback.setNeighborDiscoveryOffload(true); sendMessage(CMD_START, new ProvisioningConfiguration(req)); } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 2f20a4bf2228..26eed24c4f39 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -70,6 +70,7 @@ import android.util.LogPrinter; import com.android.internal.util.WakeupMessage; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; +import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import java.net.InetAddress; @@ -223,11 +224,15 @@ public class ConnectivityServiceTest extends AndroidTestCase { private final NetworkCapabilities mNetworkCapabilities; private final IdleableHandlerThread mHandlerThread; private final ConditionVariable mDisconnected = new ConditionVariable(); + private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); private int mScore; private NetworkAgent mNetworkAgent; private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED; private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE; private Integer mExpectedKeepaliveSlot = null; + // Contains the redirectUrl from networkStatus(). Before reading, wait for + // mNetworkStatusReceived. + private String mRedirectUrl; MockNetworkAgent(int transport) { final int type = transportToLegacyType(transport); @@ -266,6 +271,12 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void stopPacketKeepalive(Message msg) { onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError); } + + @Override + public void networkStatus(int status, String redirectUrl) { + mRedirectUrl = redirectUrl; + mNetworkStatusReceived.open(); + } }; // Waits for the NetworkAgent to be registered, which includes the creation of the // NetworkMonitor. @@ -340,13 +351,15 @@ public class ConnectivityServiceTest extends AndroidTestCase { if (callback != null) mCm.unregisterNetworkCallback(callback); } - public void connectWithCaptivePortal() { + public void connectWithCaptivePortal(String redirectUrl) { mWrappedNetworkMonitor.gen204ProbeResult = 200; + mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl; connect(false); waitFor(new Criteria() { public boolean get() { NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork()); return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} }); mWrappedNetworkMonitor.gen204ProbeResult = 500; + mWrappedNetworkMonitor.gen204ProbeRedirectUrl = null; } public void disconnect() { @@ -381,6 +394,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void setExpectedKeepaliveSlot(Integer slot) { mExpectedKeepaliveSlot = slot; } + + public String waitForRedirectUrl() { + assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS)); + return mRedirectUrl; + } } /** @@ -543,6 +561,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private class WrappedNetworkMonitor extends NetworkMonitor { // HTTP response code fed back to NetworkMonitor for Internet connectivity probe. public int gen204ProbeResult = 500; + public String gen204ProbeRedirectUrl = null; public WrappedNetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) { @@ -550,8 +569,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @Override - protected int isCaptivePortal() { - return gen204ProbeResult; + protected CaptivePortalProbeResult isCaptivePortal() { + return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl); } @Override @@ -1344,8 +1363,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(); + String firstRedirectUrl = "http://example.com/firstPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); captivePortalCallback.expectCallback(CallbackState.AVAILABLE); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); // Take down network. // Expect onLost callback. @@ -1355,8 +1376,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(); + String secondRedirectUrl = "http://example.com/secondPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); captivePortalCallback.expectCallback(CallbackState.AVAILABLE); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl); // Make captive portal disappear then revalidate. // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL. diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java index dae84471d40e..7d28e3964f8e 100644 --- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java @@ -87,6 +87,12 @@ public class LockSettingsStorageTests extends AndroidTestCase { return new File(mStorageDir, super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath(); } + + @Override + String getChildProfileLockFile(int userId) { + return new File(mStorageDir, + super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath(); + } }; } @@ -235,6 +241,27 @@ public class LockSettingsStorageTests extends AndroidTestCase { assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash); } + public void testLockType_WriteProfileWritesParent() { + mStorage.writePasswordHash("parentpassword".getBytes(), 10); + mStorage.writePatternHash("12345678".getBytes(), 20); + + assertEquals(2, mStorage.getStoredCredentialType(10)); + assertEquals(1, mStorage.getStoredCredentialType(20)); + mStorage.clearCache(); + assertEquals(2, mStorage.getStoredCredentialType(10)); + assertEquals(1, mStorage.getStoredCredentialType(20)); + } + + public void testProfileLock_ReadWriteChildProfileLock() { + assertFalse(mStorage.hasChildProfileLock(20)); + mStorage.writeChildProfileLock(20, "profilepassword".getBytes()); + assertArrayEquals("profilepassword".getBytes(), mStorage.readChildProfileLock(20)); + assertTrue(mStorage.hasChildProfileLock(20)); + mStorage.clearCache(); + assertArrayEquals("profilepassword".getBytes(), mStorage.readChildProfileLock(20)); + assertTrue(mStorage.hasChildProfileLock(20)); + } + public void testPassword_WriteParentWritesProfile() { mStorage.writePasswordHash("profilepassword".getBytes(), 2); mStorage.writePasswordHash("parentpasswordd".getBytes(), 1); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java index 2fd11da3adf3..ce02a79005ba 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java @@ -216,7 +216,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { String injectShortcutManagerConstants() { return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + "," + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + "," - + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=" + MAX_DAILY_UPDATES + "," + + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=" + + MAX_UPDATES_PER_INTERVAL + "," + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + "," + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=" + MAX_ICON_DIMENSION_LOWRAM + "," @@ -465,7 +466,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { private static final int MAX_SHORTCUTS = 10; - private static final int MAX_DAILY_UPDATES = 3; + private static final int MAX_UPDATES_PER_INTERVAL = 3; private static final int MAX_ICON_DIMENSION = 128; @@ -1074,7 +1075,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL); - // Advance further; 4 days since start. + // Advance further; 4 hours since start. mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50; assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL); @@ -1111,14 +1112,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase { mService.updateConfigurationLocked( ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123," + ConfigConstants.KEY_MAX_SHORTCUTS + "=4," - + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=5," + + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=5," + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100," + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50," + ConfigConstants.KEY_ICON_FORMAT + "=WEBP," + ConfigConstants.KEY_ICON_QUALITY + "=75"); assertEquals(123000, mService.getResetIntervalForTest()); assertEquals(4, mService.getMaxDynamicShortcutsForTest()); - assertEquals(5, mService.getMaxDailyUpdatesForTest()); + assertEquals(5, mService.getMaxUpdatesPerIntervalForTest()); assertEquals(100, mService.getMaxIconDimensionForTest()); assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest()); assertEquals(75, mService.getIconPersistQualityForTest()); @@ -1134,8 +1135,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP, mService.getMaxDynamicShortcutsForTest()); - assertEquals(ShortcutService.DEFAULT_MAX_DAILY_UPDATES, - mService.getMaxDailyUpdatesForTest()); + assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL, + mService.getMaxUpdatesPerIntervalForTest()); assertEquals(50, mService.getMaxIconDimensionForTest()); @@ -1154,7 +1155,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { /** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */ public void testGetRemainingCallCount() { - assertEquals(MAX_DAILY_UPDATES, mManager.getRemainingCallCount()); + assertEquals(MAX_UPDATES_PER_INTERVAL, mManager.getRemainingCallCount()); } /** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */ @@ -1241,61 +1242,71 @@ public class ShortcutManagerTest extends InstrumentationTestCase { mManager.getDynamicShortcuts()), "shortcut1"); - assertTrue(mManager.addDynamicShortcut(si2)); + assertTrue(mManager.addDynamicShortcuts(list(si2, si3))); assertEquals(1, mManager.getRemainingCallCount()); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut1", "shortcut2"); + "shortcut1", "shortcut2", "shortcut3"); - // Add with the same ID - assertTrue(mManager.addDynamicShortcut(makeShortcut("shortcut1"))); + // This should not crash. It'll still consume the quota. + assertTrue(mManager.addDynamicShortcuts(list())); assertEquals(0, mManager.getRemainingCallCount()); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut1", "shortcut2"); + "shortcut1", "shortcut2", "shortcut3"); + + mInjectedCurrentTimeLillis += INTERVAL; // reset + + // Add with the same ID + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("shortcut1")))); + assertEquals(2, mManager.getRemainingCallCount()); + assertShortcutIds(assertAllNotKeyFieldsOnly( + mManager.getDynamicShortcuts()), + "shortcut1", "shortcut2", "shortcut3"); // TODO Check max number // TODO Check fields. runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); }); } - public void testDeleteDynamicShortcut() { + public void testDeleteDynamicShortcuts() { final ShortcutInfo si1 = makeShortcut("shortcut1"); final ShortcutInfo si2 = makeShortcut("shortcut2"); final ShortcutInfo si3 = makeShortcut("shortcut3"); + final ShortcutInfo si4 = makeShortcut("shortcut4"); - assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3))); + assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3, si4))); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut1", "shortcut2", "shortcut3"); + "shortcut1", "shortcut2", "shortcut3", "shortcut4"); assertEquals(2, mManager.getRemainingCallCount()); - mManager.deleteDynamicShortcut("shortcut1"); + mManager.removeDynamicShortcuts(list("shortcut1")); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut2", "shortcut3"); + "shortcut2", "shortcut3", "shortcut4"); - mManager.deleteDynamicShortcut("shortcut1"); + mManager.removeDynamicShortcuts(list("shortcut1")); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut2", "shortcut3"); + "shortcut2", "shortcut3", "shortcut4"); - mManager.deleteDynamicShortcut("shortcutXXX"); + mManager.removeDynamicShortcuts(list("shortcutXXX")); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut2", "shortcut3"); + "shortcut2", "shortcut3", "shortcut4"); - mManager.deleteDynamicShortcut("shortcut2"); + mManager.removeDynamicShortcuts(list("shortcut2", "shortcut4")); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), "shortcut3"); - mManager.deleteDynamicShortcut("shortcut3"); + mManager.removeDynamicShortcuts(list("shortcut3")); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts())); @@ -1315,7 +1326,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(2, mManager.getRemainingCallCount()); - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); assertEquals(0, mManager.getDynamicShortcuts().size()); assertEquals(2, mManager.getRemainingCallCount()); @@ -1383,7 +1394,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(0, mManager.getRemainingCallCount()); assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime()); - // 4 days later... + // 4 hours later... mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL; assertTrue(mManager.setDynamicShortcuts(list(si1))); assertEquals(2, mManager.getRemainingCallCount()); @@ -1791,13 +1802,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { getCallingUser()); }); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { - mManager.deleteDynamicShortcut("s1"); - mManager.deleteDynamicShortcut("s2"); + mManager.removeDynamicShortcuts(list("s1")); + mManager.removeDynamicShortcuts(list("s2")); }); runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { - mManager.deleteDynamicShortcut("s1"); - mManager.deleteDynamicShortcut("s3"); - mManager.deleteDynamicShortcut("s5"); + mManager.removeDynamicShortcuts(list("s1")); + mManager.removeDynamicShortcuts(list("s3")); + mManager.removeDynamicShortcuts(list("s5")); }); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { assertShortcutIds(assertAllDynamic( @@ -2089,7 +2100,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Delete some. setCaller(CALLING_PACKAGE_1); assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); - mManager.deleteDynamicShortcut("s2"); + mManager.removeDynamicShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); dumpsysOnLogcat(); @@ -2154,19 +2165,19 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Delete some. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); - mManager.deleteDynamicShortcut("s2"); + mManager.removeDynamicShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts(), "s2"); }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4"); - mManager.deleteDynamicShortcut("s3"); + mManager.removeDynamicShortcuts(list("s3")); assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4"); }); runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { assertShortcutIds(mManager.getPinnedShortcuts() /* none */); - mManager.deleteDynamicShortcut("s2"); + mManager.removeDynamicShortcuts(list("s2")); assertShortcutIds(mManager.getPinnedShortcuts() /* none */); }); @@ -2218,7 +2229,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Delete some. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s3"); - mManager.deleteDynamicShortcut("s3"); + mManager.removeDynamicShortcuts(list("s3")); assertShortcutIds(mManager.getPinnedShortcuts(), "s3"); }); @@ -2226,8 +2237,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2"); - mManager.deleteDynamicShortcut("s1"); - mManager.deleteDynamicShortcut("s3"); + mManager.removeDynamicShortcuts(list("s1")); + mManager.removeDynamicShortcuts(list("s3")); assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2"); }); @@ -2336,13 +2347,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Delete all dynamic. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3"); }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); assertEquals(0, mManager.getDynamicShortcuts().size()); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1"); @@ -2377,7 +2388,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { }); // Re-publish s1. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1"); assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3"); @@ -2979,7 +2990,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Just to make it complicated, delete some. setCaller(CALLING_PACKAGE_1); - mManager.deleteDynamicShortcut("s2"); + mManager.removeDynamicShortcuts(list("s2")); // intent and check. setCaller(LAUNCHER_1); @@ -3051,11 +3062,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase { any(UserHandle.class) ); - // Test for addDynamicShortcut. + // Test for addDynamicShortcuts. reset(c0); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { - dumpsysOnLogcat("before addDynamicShortcut"); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s4"))); + dumpsysOnLogcat("before addDynamicShortcuts"); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4")))); }); waitOnMainThread(); @@ -3071,7 +3082,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Test for remove reset(c0); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { - mManager.deleteDynamicShortcut("s1"); + mManager.removeDynamicShortcuts(list("s1")); }); waitOnMainThread(); @@ -3104,7 +3115,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Test for deleteAll reset(c0); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); }); waitOnMainThread(); @@ -3178,7 +3189,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { resetAll(all); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - mManager.deleteDynamicShortcut("x"); + mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3195,7 +3206,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { resetAll(all); runWithCaller(CALLING_PACKAGE_3, USER_0, () -> { - mManager.deleteDynamicShortcut("x"); + mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3213,7 +3224,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { resetAll(all); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { - mManager.deleteDynamicShortcut("x"); + mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3233,7 +3244,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { resetAll(all); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { - mManager.deleteDynamicShortcut("x"); + mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3253,7 +3264,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { resetAll(all); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { - mManager.deleteDynamicShortcut("x"); + mManager.removeDynamicShortcuts(list()); }); waitOnMainThread(); @@ -3477,16 +3488,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Remove all dynamic shortcuts; now all shortcuts are just pinned. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); }); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); }); runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { - mManager.deleteAllDynamicShortcuts(); + mManager.removeAllDynamicShortcuts(); }); @@ -4009,22 +4020,22 @@ public class ShortcutManagerTest extends InstrumentationTestCase { public void testHandlePackageDelete() { setCaller(CALLING_PACKAGE_1, USER_0); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); setCaller(CALLING_PACKAGE_2, USER_0); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); setCaller(CALLING_PACKAGE_3, USER_0); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); setCaller(CALLING_PACKAGE_1, USER_10); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); setCaller(CALLING_PACKAGE_2, USER_10); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); setCaller(CALLING_PACKAGE_3, USER_10); - assertTrue(mManager.addDynamicShortcut(makeShortcut("s1"))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); @@ -4980,6 +4991,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { .setTitle("title") .setText("text") .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setWeight(123) .setExtras(pb) .build(); @@ -4995,6 +5007,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals("content://a.b.c/", si.getIcon().getUriString()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getWeight()); @@ -5016,6 +5029,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { .setIcon(Icon.createWithContentUri("content://a.b.c/")) .setTitle("title") .setText("text") + .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setWeight(123) .setExtras(pb) @@ -5034,6 +5048,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals("content://a.b.c/", si.getIcon().getUriString()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getWeight()); @@ -5051,6 +5066,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(null, si.getIcon()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getWeight()); @@ -5058,7 +5074,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); assertEquals(null, si.getBitmapPath()); - assertEquals(0, si.getIconResourceId()); + + assertEquals(456, si.getIconResourceId()); si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER); @@ -5068,13 +5085,15 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(null, si.getIcon()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals(null, si.getIntent()); assertEquals(123, si.getWeight()); assertEquals(1, si.getExtras().getInt("k")); assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); assertEquals(null, si.getBitmapPath()); - assertEquals(0, si.getIconResourceId()); + + assertEquals(456, si.getIconResourceId()); si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); @@ -5084,13 +5103,56 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(null, si.getIcon()); assertEquals(null, si.getTitle()); assertEquals(null, si.getText()); + assertEquals(null, si.getCategories()); assertEquals(null, si.getIntent()); assertEquals(0, si.getWeight()); assertEquals(null, si.getExtras()); assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags()); assertEquals(null, si.getBitmapPath()); - assertEquals(0, si.getIconResourceId()); + + assertEquals(456, si.getIconResourceId()); + } + + public void testShortcutInfoClone_minimum() { + PersistableBundle pb = new PersistableBundle(); + pb.putInt("k", 1); + ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext()) + .setId("id") + .setTitle("title") + .setIntent(makeIntent("action", ShortcutActivity.class)) + .build(); + ShortcutInfo si = sorig.clone(/* clone flags*/ 0); + + assertEquals(getTestContext().getPackageName(), si.getPackageName()); + assertEquals("id", si.getId()); + assertEquals("title", si.getTitle()); + assertEquals("action", si.getIntent().getAction()); + assertEquals(null, si.getCategories()); + + si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR); + + assertEquals(getTestContext().getPackageName(), si.getPackageName()); + assertEquals("id", si.getId()); + assertEquals("title", si.getTitle()); + assertEquals("action", si.getIntent().getAction()); + assertEquals(null, si.getCategories()); + + si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER); + + assertEquals(getTestContext().getPackageName(), si.getPackageName()); + assertEquals("id", si.getId()); + assertEquals("title", si.getTitle()); + assertEquals(null, si.getIntent()); + assertEquals(null, si.getCategories()); + + si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); + + assertEquals(getTestContext().getPackageName(), si.getPackageName()); + assertEquals("id", si.getId()); + assertEquals(null, si.getTitle()); + assertEquals(null, si.getIntent()); + assertEquals(null, si.getCategories()); } public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException { @@ -5102,6 +5164,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { .setIcon(Icon.createWithContentUri("content://a.b.c/")) .setTitle("title") .setText("text") + .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setWeight(123) .setExtras(pb) @@ -5115,38 +5178,57 @@ public class ShortcutManagerTest extends InstrumentationTestCase { si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setActivityComponent(new ComponentName("x", "y")).build()); + assertEquals("text", si.getText()); assertEquals(new ComponentName("x", "y"), si.getActivityComponent()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setIcon(Icon.createWithContentUri("content://x.y.z/")).build()); + assertEquals("text", si.getText()); assertEquals("content://x.y.z/", si.getIcon().getUriString()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setTitle("xyz").build()); + assertEquals("text", si.getText()); assertEquals("xyz", si.getTitle()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setText("xxx").build()); + assertEquals(123, si.getWeight()); assertEquals("xxx", si.getText()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") + .setCategories(list()).build()); + assertEquals("text", si.getText()); + assertEquals(list(), si.getCategories()); + + si = sorig.clone(/* flags=*/ 0); + si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") + .setCategories(list("x")).build()); + assertEquals("text", si.getText()); + assertEquals(list("x"), si.getCategories()); + + si = sorig.clone(/* flags=*/ 0); + si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setIntent(makeIntent("action2", ShortcutActivity.class)).build()); + assertEquals("text", si.getText()); assertEquals("action2", si.getIntent().getAction()); assertEquals(null, si.getIntent().getStringExtra("key")); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build()); + assertEquals("text", si.getText()); assertEquals("action3", si.getIntent().getAction()); assertEquals("x", si.getIntent().getStringExtra("key")); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setWeight(999).build()); + assertEquals("text", si.getText()); assertEquals(999, si.getWeight()); @@ -5156,8 +5238,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase { si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setExtras(pb2).build()); + assertEquals("text", si.getText()); assertEquals(99, si.getExtras().getInt("x")); + // Make sure the timestamp gets updated too. + final long timestamp = si.getLastChangedTimestamp(); Thread.sleep(2); @@ -5181,12 +5266,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { .setIcon(bmp32x32) .setTitle("title") .setText("text") + .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setWeight(123) .setExtras(pb) .build(); - mManager.addDynamicShortcut(sorig); + mManager.addDynamicShortcuts(list(sorig)); Thread.sleep(2); final long now = System.currentTimeMillis(); @@ -5207,6 +5293,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(null, si.getIcon()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getWeight()); @@ -5232,12 +5319,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { .setIcon(bmp32x32) .setTitle("title") .setText("text") + .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setWeight(123) .setExtras(pb) .build(); - mManager.addDynamicShortcut(sorig); + mManager.addDynamicShortcuts(list(sorig)); // Dynamic shortcuts won't be backed up, so we need to pin it. setCaller(LAUNCHER_1, USER_0); @@ -5246,6 +5334,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { // Do backup & restore. backupAndRestore(); + mService.handleUnlockUser(USER_0); // Load user-0. + ShortcutInfo si; si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0); @@ -5255,6 +5345,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(null, si.getIcon()); assertEquals("title", si.getTitle()); assertEquals("text", si.getText()); + assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getWeight()); diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java new file mode 100644 index 000000000000..26b87c5d9283 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package com.android.server.webkit; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.webkit.WebViewProviderInfo; + +import java.util.HashMap; + +public class TestSystemImpl implements SystemInterface { + private String mUserProvider = ""; + private final WebViewProviderInfo[] mPackageConfigs; + HashMap<String, PackageInfo> mPackages = new HashMap(); + private boolean mFallbackLogicEnabled; + private final int mNumRelros; + private final boolean mIsDebuggable; + + public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled, + int numRelros, boolean isDebuggable) { + mPackageConfigs = packageConfigs; + mFallbackLogicEnabled = fallbackLogicEnabled; + mNumRelros = numRelros; + mIsDebuggable = isDebuggable; + } + + @Override + public WebViewProviderInfo[] getWebViewPackages() { + return mPackageConfigs; + } + + @Override + public int onWebViewProviderChanged(PackageInfo packageInfo) { + return mNumRelros; + } + + @Override + public String getUserChosenWebViewProvider(Context context) { return mUserProvider; } + + @Override + public void updateUserSetting(Context context, String newProviderName) { + mUserProvider = newProviderName; + } + + @Override + public void killPackageDependents(String packageName) {} + + @Override + public boolean isFallbackLogicEnabled() { + return mFallbackLogicEnabled; + } + + @Override + public void enableFallbackLogic(boolean enable) { + mFallbackLogicEnabled = enable; + } + + @Override + public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) { + enablePackageForAllUsers(context, packageName, false); + } + + @Override + public void enablePackageForAllUsers(Context context, String packageName, boolean enable) { + enablePackageForUser(packageName, enable, 0); + } + + @Override + public void enablePackageForUser(String packageName, boolean enable, int userId) { + PackageInfo packageInfo = mPackages.get(packageName); + if (packageInfo == null) { + throw new IllegalArgumentException("There is no package called " + packageName); + } + packageInfo.applicationInfo.enabled = enable; + setPackageInfo(packageInfo); + } + + @Override + public boolean systemIsDebuggable() { return mIsDebuggable; } + + @Override + public PackageInfo getPackageInfoForProvider(WebViewProviderInfo info) throws + NameNotFoundException { + PackageInfo ret = mPackages.get(info.packageName); + if (ret == null) throw new NameNotFoundException(info.packageName); + return ret; + } + + public void setPackageInfo(PackageInfo pi) { + mPackages.put(pi.packageName, pi); + } + + @Override + public int getFactoryPackageVersion(String packageName) { + return 0; + } +} diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java new file mode 100644 index 000000000000..c00520dc3552 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java @@ -0,0 +1,613 @@ +/* + * 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. + */ + +package com.android.server.webkit; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.Signature; +import android.os.Bundle; +import android.util.Base64; +import android.test.AndroidTestCase; + +import android.webkit.WebViewFactory; +import android.webkit.WebViewProviderInfo; +import android.webkit.WebViewProviderResponse; + +import java.util.concurrent.CountDownLatch; + +import org.hamcrest.Description; + +import org.mockito.Mockito; +import org.mockito.Matchers; +import org.mockito.ArgumentMatcher; + + +/** + * Tests for WebViewUpdateService + */ +public class WebViewUpdateServiceTest extends AndroidTestCase { + private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName(); + + private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl; + private TestSystemImpl mTestSystemImpl; + + private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * Creates a new instance. + */ + public WebViewUpdateServiceTest() { + } + + private void setupWithPackages(WebViewProviderInfo[] packages) { + setupWithPackages(packages, true); + } + + private void setupWithPackages(WebViewProviderInfo[] packages, + boolean fallbackLogicEnabled) { + setupWithPackages(packages, fallbackLogicEnabled, 1); + } + + private void setupWithPackages(WebViewProviderInfo[] packages, + boolean fallbackLogicEnabled, int numRelros) { + setupWithPackages(packages, fallbackLogicEnabled, numRelros, + true /* isDebuggable == true -> don't check package signatures */); + } + + private void setupWithPackages(WebViewProviderInfo[] packages, + boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) { + TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros, + isDebuggable); + mTestSystemImpl = Mockito.spy(testing); + mWebViewUpdateServiceImpl = + new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl); + } + + private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) { + for(WebViewProviderInfo wpi : providers) { + mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */, + true /* valid */)); + } + } + + private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName, + WebViewProviderInfo[] webviewPackages) { + checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1); + } + + private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName, + WebViewProviderInfo[] webviewPackages, int numRelros) { + setupWithPackages(webviewPackages, true, numRelros); + // Add (enabled and valid) package infos for each provider + setEnabledAndValidPackageInfos(webviewPackages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(expectedProviderName))); + + for (int n = 0; n < numRelros; n++) { + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + } + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); + assertEquals(expectedProviderName, response.packageInfo.packageName); + } + + // For matching the package name of a PackageInfo + private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> { + private final String mPackageName; + + IsPackageInfoWithName(String name) { + mPackageName = name; + } + + @Override + public boolean matches(Object p) { + return ((PackageInfo) p).packageName.equals(mPackageName); + } + + // Provide a more useful description in case of mismatch + @Override + public void describeTo (Description description) { + description.appendText(String.format("PackageInfo with name '%s'", mPackageName)); + } + } + + private static PackageInfo createPackageInfo( + String packageName, boolean enabled, boolean valid) { + PackageInfo p = new PackageInfo(); + p.packageName = packageName; + p.applicationInfo = new ApplicationInfo(); + p.applicationInfo.enabled = enabled; + p.applicationInfo.metaData = new Bundle(); + if (valid) { + // no flag means invalid + p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah"); + } + return p; + } + + private static PackageInfo createPackageInfo( + String packageName, boolean enabled, boolean valid, Signature[] signatures) { + PackageInfo p = createPackageInfo(packageName, enabled, valid); + p.signatures = signatures; + return p; + } + + + // **************** + // Tests + // **************** + + + public void testWithSinglePackage() { + String testPackageName = "test.package.name"; + checkCertainPackageUsedAfterWebViewPreparation(testPackageName, + new WebViewProviderInfo[] { + new WebViewProviderInfo(testPackageName, "", + true /*default available*/, false /* fallback */, null)}); + } + + public void testDefaultPackageUsedOverNonDefault() { + String defaultPackage = "defaultPackage"; + String nonDefaultPackage = "nonDefaultPackage"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(nonDefaultPackage, "", false, false, null), + new WebViewProviderInfo(defaultPackage, "", true, false, null)}; + checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages); + } + + public void testSeveralRelros() { + String singlePackage = "singlePackage"; + checkCertainPackageUsedAfterWebViewPreparation( + singlePackage, + new WebViewProviderInfo[] { + new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)}, + 2); + } + + // Ensure that package with valid signatures is chosen rather than package with invalid + // signatures. + public void testWithSignatures() { + String validPackage = "valid package"; + String invalidPackage = "invalid package"; + + Signature validSignature = new Signature("11"); + Signature invalidExpectedSignature = new Signature("22"); + Signature invalidPackageSignature = new Signature("33"); + + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{ + Base64.encodeToString( + invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}), + new WebViewProviderInfo(validPackage, "", true, false, new String[]{ + Base64.encodeToString( + validSignature.toByteArray(), Base64.DEFAULT)}) + }; + setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */, + false /* isDebuggable */); + mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */, + true /* valid */, new Signature[]{invalidPackageSignature})); + mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */, + true /* valid */, new Signature[]{validSignature})); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(validPackage))); + + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); + assertEquals(validPackage, response.packageInfo.packageName); + + WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages(); + assertEquals(1, validPackages.length); + assertEquals(validPackage, validPackages[0].packageName); + } + + public void testFailWaitingForRelro() { + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo("packagename", "", true, true, null)}; + setupWithPackages(packages); + setEnabledAndValidPackageInfos(packages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName))); + + // Never call notifyRelroCreation() + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status); + } + + public void testFailListingEmptyWebviewPackages() { + WebViewProviderInfo[] packages = new WebViewProviderInfo[0]; + setupWithPackages(packages); + setEnabledAndValidPackageInfos(packages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged( + Matchers.anyObject()); + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); + } + + public void testFailListingInvalidWebviewPackage() { + WebViewProviderInfo wpi = new WebViewProviderInfo("", "", true, true, null); + WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi}; + setupWithPackages(packages); + mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true, false)); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); + } + + // Test that switching provider using changeProviderAndSetting works. + public void testSwitchingProvider() { + String firstPackage = "first"; + String secondPackage = "second"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(firstPackage, "", true, false, null), + new WebViewProviderInfo(secondPackage, "", true, false, null)}; + checkSwitchingProvider(packages, firstPackage, secondPackage); + } + + public void testSwitchingProviderToNonDefault() { + String defaultPackage = "defaultPackage"; + String nonDefaultPackage = "nonDefaultPackage"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(defaultPackage, "", true, false, null), + new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)}; + checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage); + } + + private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage, + String finalPackage) { + checkCertainPackageUsedAfterWebViewPreparation(initialPackage, packages); + + mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(finalPackage))); + + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + + WebViewProviderResponse secondResponse = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, secondResponse.status); + assertEquals(finalPackage, secondResponse.packageInfo.packageName); + + Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage)); + } + + // Change provider during relro creation by using changeProviderAndSetting + public void testSwitchingProviderDuringRelroCreation() { + checkChangingProviderDuringRelroCreation(true); + } + + // Change provider during relro creation by enabling a provider + public void testChangingProviderThroughEnablingDuringRelroCreation() { + checkChangingProviderDuringRelroCreation(false); + } + + private void checkChangingProviderDuringRelroCreation(boolean settingsChange) { + String firstPackage = "first"; + String secondPackage = "second"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(firstPackage, "", true, false, null), + new WebViewProviderInfo(secondPackage, "", true, false, null)}; + setupWithPackages(packages); + if (settingsChange) { + // Have all packages be enabled, so that we can change provider however we want to + setEnabledAndValidPackageInfos(packages); + } else { + // Have all packages be disabled so that we can change one to enabled later + for(WebViewProviderInfo wpi : packages) { + mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, + false /* enabled */, true /* valid */)); + } + } + + CountDownLatch countdown = new CountDownLatch(1); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(firstPackage))); + + assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName()); + + new Thread(new Runnable() { + @Override + public void run() { + WebViewProviderResponse threadResponse = + mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status); + assertEquals(secondPackage, threadResponse.packageInfo.packageName); + // Verify that we killed the first package + Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage)); + countdown.countDown(); + } + }).start(); + try { + Thread.sleep(1000); // Let the new thread run / be blocked + } catch (InterruptedException e) { + } + + if (settingsChange) { + mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); + } else { + // Switch provider by enabling the second one + mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, + true /* valid */)); + mWebViewUpdateServiceImpl.packageStateChanged( + secondPackage, WebViewUpdateService.PACKAGE_CHANGED); + } + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + // first package done, should start on second + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(secondPackage))); + + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + // second package done, the other thread should now be unblocked + try { + countdown.await(); + } catch (InterruptedException e) { + } + } + + public void testRunFallbackLogicIfEnabled() { + checkFallbackLogicBeingRun(true); + } + + public void testDontRunFallbackLogicIfDisabled() { + checkFallbackLogicBeingRun(false); + } + + private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) { + String primaryPackage = "primary"; + String fallbackPackage = "fallback"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo( + primaryPackage, "", true /* default available */, false /* fallback */, null), + new WebViewProviderInfo( + fallbackPackage, "", true /* default available */, true /* fallback */, null)}; + setupWithPackages(packages, fallbackLogicEnabled); + setEnabledAndValidPackageInfos(packages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + // Verify that we disable the fallback package if fallback logic enabled, and don't disable + // the fallback package if that logic is disabled + if (fallbackLogicEnabled) { + Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Mockito.eq(fallbackPackage)); + } else { + Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Matchers.anyObject()); + } + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); + + // Enable fallback package + mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */, + true /* valid */)); + mWebViewUpdateServiceImpl.packageStateChanged( + fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED); + + if (fallbackLogicEnabled) { + // Check that we have now disabled the fallback package twice + Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Mockito.eq(fallbackPackage)); + } else { + // Check that we still haven't disabled any package + Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Matchers.anyObject()); + } + } + + /** + * Scenario for installing primary package when fallback enabled. + * 1. Start with only fallback installed + * 2. Install non-fallback + * 3. Fallback should be disabled + */ + public void testInstallingNonFallbackPackage() { + String primaryPackage = "primary"; + String fallbackPackage = "fallback"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo( + primaryPackage, "", true /* default available */, false /* fallback */, null), + new WebViewProviderInfo( + fallbackPackage, "", true /* default available */, true /* fallback */, null)}; + setupWithPackages(packages, true /* isFallbackLogicEnabled */); + mTestSystemImpl.setPackageInfo( + createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */)); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Matchers.anyObject()); + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(fallbackPackage))); + + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); + assertEquals(fallbackPackage, response.packageInfo.packageName); + + // Install primary package + mTestSystemImpl.setPackageInfo( + createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */)); + mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, + WebViewUpdateService.PACKAGE_ADDED); + + // Verify fallback disabled and primary package used as provider + Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers( + Matchers.anyObject(), Mockito.eq(fallbackPackage)); + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(primaryPackage))); + + // Finish the webview preparation and ensure primary package used and fallback killed + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); + assertEquals(primaryPackage, response.packageInfo.packageName); + Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage)); + } + + public void testFallbackChangesEnabledState() { + String primaryPackage = "primary"; + String fallbackPackage = "fallback"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo( + primaryPackage, "", true /* default available */, false /* fallback */, null), + new WebViewProviderInfo( + fallbackPackage, "", true /* default available */, true /* fallback */, null)}; + setupWithPackages(packages, true /* fallbackLogicEnabled */); + setEnabledAndValidPackageInfos(packages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + // Verify fallback disabled at boot when primary package enabled + Mockito.verify(mTestSystemImpl).enablePackageForUser( + Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, + Matchers.anyInt()); + + mTestSystemImpl.setPackageInfo( + createPackageInfo(primaryPackage, false /* enabled */, true /* valid */)); + mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, + WebViewUpdateService.PACKAGE_CHANGED); + + // Verify fallback becomes enabled when primary package becomes disabled + Mockito.verify(mTestSystemImpl).enablePackageForUser( + Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */, + Matchers.anyInt()); + + mTestSystemImpl.setPackageInfo( + createPackageInfo(primaryPackage, true /* enabled */, true /* valid */)); + mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage, + WebViewUpdateService.PACKAGE_CHANGED); + + // Verify fallback is disabled a second time when primary package becomes enabled + Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser( + Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, + Matchers.anyInt()); + } + + public void testAddUserWhenFallbackLogicEnabled() { + checkAddingNewUser(true); + } + + public void testAddUserWhenFallbackLogicDisabled() { + checkAddingNewUser(false); + } + + public void checkAddingNewUser(boolean fallbackLogicEnabled) { + String primaryPackage = "primary"; + String fallbackPackage = "fallback"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo( + primaryPackage, "", true /* default available */, false /* fallback */, null), + new WebViewProviderInfo( + fallbackPackage, "", true /* default available */, true /* fallback */, null)}; + setupWithPackages(packages, fallbackLogicEnabled); + setEnabledAndValidPackageInfos(packages); + int newUser = 100; + mWebViewUpdateServiceImpl.handleNewUser(newUser); + if (fallbackLogicEnabled) { + // Verify fallback package becomes disabled for new user + Mockito.verify(mTestSystemImpl).enablePackageForUser( + Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */, + Mockito.eq(newUser)); + } else { + // Verify that we don't disable fallback for new user + Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser( + Mockito.anyObject(), Matchers.anyBoolean() /* enable */, + Matchers.anyInt() /* user */); + } + } + + /** + * Timing dependent test where we verify that the list of valid webview packages becoming empty + * at a certain point doesn't crash us or break our state. + */ + public void testNotifyRelroDoesntCrashIfNoPackages() { + String firstPackage = "first"; + String secondPackage = "second"; + WebViewProviderInfo[] packages = new WebViewProviderInfo[] { + new WebViewProviderInfo(firstPackage, "", true /* default available */, + false /* fallback */, null), + new WebViewProviderInfo(secondPackage, "", true /* default available */, + false /* fallback */, null)}; + setupWithPackages(packages); + // Add (enabled and valid) package infos for each provider + setEnabledAndValidPackageInfos(packages); + + mWebViewUpdateServiceImpl.prepareWebViewInSystemServer(); + + Mockito.verify(mTestSystemImpl).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(firstPackage))); + + mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage); + + // Make packages invalid to cause exception to be thrown + mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, + false /* valid */)); + mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */, + false /* valid */)); + + // This shouldn't throw an exception! + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + + WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status); + + // Now make a package valid again and verify that we can switch back to that + mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */, + true /* valid */)); + + mWebViewUpdateServiceImpl.packageStateChanged(firstPackage, + WebViewUpdateService.PACKAGE_ADDED); + + // Second time we call onWebViewProviderChanged for firstPackage + Mockito.verify(mTestSystemImpl, Mockito.times(2)).onWebViewProviderChanged( + Mockito.argThat(new IsPackageInfoWithName(firstPackage))); + + mWebViewUpdateServiceImpl.notifyRelroCreationCompleted(); + + response = mWebViewUpdateServiceImpl.waitForAndGetProvider(); + assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status); + assertEquals(firstPackage, response.packageInfo.packageName); + } + + // TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called +} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index adc7c218799b..c18c13c44aca 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -426,6 +426,13 @@ public class CarrierConfigManager { public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS = "carrier_metered_apn_types_strings"; + /** + * CDMA carrier ERI (Enhanced Roaming Indicator) file name + * @hide + */ + public static final String KEY_CARRIER_ERI_FILE_NAME_STRING = + "carrier_eri_file_name_string"; + /* The following 3 fields are related to carrier visual voicemail. */ /** @@ -705,6 +712,7 @@ public class CarrierConfigManager { "max_retries=3, 5000, 5000, 5000"); sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000); sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000); + sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml"); sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200); sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS, new String[]{"default", "mms", "dun", "supl"}); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 865af7821ac2..638b286987b6 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -717,16 +717,11 @@ public class TelephonyManager { */ /** {@hide} */ public String getDeviceSoftwareVersion(int slotId) { - // FIXME methods taking slot id should not use subscription, instead us Uicc directly - int[] subId = SubscriptionManager.getSubId(slotId); - if (subId == null || subId.length == 0) { - return null; - } + ITelephony telephony = getITelephony(); + if (telephony == null) return null; + try { - IPhoneSubInfo info = getSubscriberInfo(); - if (info == null) - return null; - return info.getDeviceSvnUsingSubId(subId[0], mContext.getOpPackageName()); + return telephony.getDeviceSoftwareVersionForSlot(slotId, getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -798,12 +793,11 @@ public class TelephonyManager { */ /** {@hide} */ public String getImei(int slotId) { - int[] subId = SubscriptionManager.getSubId(slotId); + ITelephony telephony = getITelephony(); + if (telephony == null) return null; + try { - IPhoneSubInfo info = getSubscriberInfo(); - if (info == null) - return null; - return info.getImeiForSubscriber(subId[0], mContext.getOpPackageName()); + return telephony.getImeiForSlot(slotId, getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1014,22 +1008,32 @@ public class TelephonyManager { } else { phoneId = SubscriptionManager.getPhoneId(subId); } + + return getCurrentPhoneTypeForSlot(phoneId); + } + + /** + * See getCurrentPhoneType. + * + * @hide + */ + public int getCurrentPhoneTypeForSlot(int slotId) { try{ ITelephony telephony = getITelephony(); - if (telephony != null && subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - return telephony.getActivePhoneTypeForSubscriber(subId); + if (telephony != null) { + return telephony.getActivePhoneTypeForSlot(slotId); } else { // This can happen when the ITelephony interface is not up yet. - return getPhoneTypeFromProperty(phoneId); + return getPhoneTypeFromProperty(slotId); } } catch (RemoteException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(phoneId); + return getPhoneTypeFromProperty(slotId); } catch (NullPointerException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(phoneId); + return getPhoneTypeFromProperty(slotId); } } @@ -2555,20 +2559,31 @@ public class TelephonyManager { * @param subId whose call state is returned */ public int getCallState(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getCallStateForSlot(phoneId); + } + + /** + * See getCallState. + * + * @hide + */ + public int getCallStateForSlot(int slotId) { try { ITelephony telephony = getITelephony(); if (telephony == null) return CALL_STATE_IDLE; - return telephony.getCallStateForSubscriber(subId); + return telephony.getCallStateForSlot(slotId); } catch (RemoteException ex) { // the phone process is restarting. return CALL_STATE_IDLE; } catch (NullPointerException ex) { // the phone process is restarting. return CALL_STATE_IDLE; - } + } } + /** Data connection activity: No traffic. */ public static final int DATA_ACTIVITY_NONE = 0x00000000; /** Data connection activity: Currently receiving IP PPP traffic. */ diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2727319ad0a6..b41d361f6a16 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -360,9 +360,9 @@ interface ITelephony { int getCallState(); /** - * Returns the call state for a subId. + * Returns the call state for a slot. */ - int getCallStateForSubscriber(int subId); + int getCallStateForSlot(int slotId); int getDataActivity(); int getDataState(); @@ -375,12 +375,12 @@ interface ITelephony { int getActivePhoneType(); /** - * Returns the current active phone type as integer for particular subId. + * Returns the current active phone type as integer for particular slot. * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE - * @param subId user preferred subId. + * @param slotId - slot to query. */ - int getActivePhoneTypeForSubscriber(int subId); + int getActivePhoneTypeForSlot(int slotId); /** * Returns the CDMA ERI icon index to display @@ -992,6 +992,26 @@ interface ITelephony { String getDeviceId(String callingPackage); /** + * Returns the IMEI for the given slot. + * + * @param slotId - device slot. + * @param callingPackage The package making the call. + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + */ + String getImeiForSlot(int slotId, String callingPackage); + + /** + * Returns the device software version. + * + * @param slotId - device slot. + * @param callingPackage The package making the call. + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + */ + String getDeviceSoftwareVersionForSlot(int slotId, String callingPackage); + + /** * Returns the subscription ID associated with the specified PhoneAccount. */ int getSubIdForPhoneAccount(in PhoneAccount phoneAccount); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 91e891f10f2f..2e5ed3fd3520 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -691,6 +691,15 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ + @Override + public void deleteApplicationCacheFilesAsUser(String packageName, int userId, + IPackageDataObserver observer) { + throw new UnsupportedOperationException(); + } + /** {@hide} */ @Override public void freeStorageAndNotify(String volumeUuid, long idealStorageSize, diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 18fd98528855..b9e9ac856185 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -374,6 +374,15 @@ </activity> <activity + android:name="GetBitmapSurfaceViewActivity" + android:label="SurfaceView/GetBitmap with Camera source"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="GLTextureViewActivity" android:label="TextureView/OpenGL"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java new file mode 100644 index 000000000000..d3cd7db7d46a --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package com.android.test.hwui; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.PixelCopy; +import android.graphics.PixelCopy.OnPixelCopyFinished; +import android.graphics.PixelCopy.Response; +import android.hardware.Camera; +import android.os.Bundle; +import android.os.Environment; +import android.view.Gravity; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.Toast; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class GetBitmapSurfaceViewActivity extends Activity implements SurfaceHolder.Callback { + private Camera mCamera; + private SurfaceView mSurfaceView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + FrameLayout content = new FrameLayout(this); + + mSurfaceView = new SurfaceView(this); + mSurfaceView.getHolder().addCallback(this); + + Button button = new Button(this); + button.setText("Copy bitmap to /sdcard/surfaceview.png"); + button.setOnClickListener((View v) -> { + Bitmap b = Bitmap.createBitmap( + mSurfaceView.getWidth(), + mSurfaceView.getHeight(), + Bitmap.Config.ARGB_8888); + PixelCopy.request(mSurfaceView, b, + mOnCopyFinished, mSurfaceView.getHandler()); + }); + + content.addView(mSurfaceView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER)); + content.addView(button, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + setContentView(content); + } + + private final OnPixelCopyFinished mOnCopyFinished = new OnPixelCopyFinished() { + @Override + public void onPixelCopyFinished(Response response) { + if (!response.success) { + Toast.makeText(GetBitmapSurfaceViewActivity.this, + "Failed to copy", Toast.LENGTH_SHORT).show(); + return; + } + try { + try (FileOutputStream out = new FileOutputStream( + Environment.getExternalStorageDirectory() + "/surfaceview.png");) { + response.bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + } + } catch (Exception e) { + // Ignore + } + } + }; + + @Override + public void surfaceCreated(SurfaceHolder holder) { + mCamera = Camera.open(); + + try { + mCamera.setPreviewSurface(holder.getSurface()); + } catch (IOException t) { + android.util.Log.e("TextureView", "Cannot set preview texture target!", t); + } + + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + mCamera.stopPreview(); + mCamera.release(); + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java index b1431c586631..5c30faba3d18 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java @@ -17,18 +17,29 @@ package com.android.test.hwui; import android.app.Activity; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PixelCopy; +import android.graphics.PixelCopy.OnPixelCopyFinished; +import android.graphics.PixelCopy.Response; import android.graphics.PorterDuff; import android.os.Bundle; -import android.view.Gravity; +import android.os.Environment; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; +import android.view.View; +import android.widget.Button; import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.Toast; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; -@SuppressWarnings({"UnusedDeclaration"}) public class HardwareCanvasSurfaceViewActivity extends Activity implements Callback { private SurfaceView mSurfaceView; private HardwareCanvasSurfaceViewActivity.RenderingThread mThread; @@ -42,13 +53,49 @@ public class HardwareCanvasSurfaceViewActivity extends Activity implements Callb mSurfaceView = new SurfaceView(this); mSurfaceView.getHolder().addCallback(this); - content.addView(mSurfaceView, new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, + Button button = new Button(this); + button.setText("Copy bitmap to /sdcard/surfaceview.png"); + button.setOnClickListener((View v) -> { + Bitmap b = Bitmap.createBitmap( + mSurfaceView.getWidth(), + mSurfaceView.getHeight(), + Bitmap.Config.ARGB_8888); + PixelCopy.request(mSurfaceView, b, + mOnCopyFinished, mSurfaceView.getHandler()); + }); + + LinearLayout layout = new LinearLayout(this); + layout.setOrientation(LinearLayout.VERTICAL); + layout.addView(button, LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + layout.addView(mSurfaceView, LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + + content.addView(layout, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, - Gravity.CENTER)); + FrameLayout.LayoutParams.MATCH_PARENT)); setContentView(content); } + private final OnPixelCopyFinished mOnCopyFinished = new OnPixelCopyFinished() { + @Override + public void onPixelCopyFinished(Response response) { + if (!response.success) { + Toast.makeText(HardwareCanvasSurfaceViewActivity.this, + "Failed to copy", Toast.LENGTH_SHORT).show(); + return; + } + try { + try (FileOutputStream out = new FileOutputStream( + Environment.getExternalStorageDirectory() + "/surfaceview.png");) { + response.bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + } + } catch (Exception e) { + // Ignore + } + } + }; + @Override public void surfaceCreated(SurfaceHolder holder) { mThread = new RenderingThread(holder.getSurface()); diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py index b5ed1b52a19d..81ab3ccf3ec5 100755 --- a/tools/fonts/fontchain_lint.py +++ b/tools/fonts/fontchain_lint.py @@ -1,13 +1,17 @@ #!/usr/bin/env python import collections +import copy import glob +import itertools from os import path import sys from xml.etree import ElementTree from fontTools import ttLib +EMOJI_VS = 0xFE0F + LANG_TO_SCRIPT = { 'as': 'Beng', 'bn': 'Beng', @@ -57,13 +61,26 @@ def lang_to_script(lang_code): return LANG_TO_SCRIPT[lang] -def get_best_cmap(font): +def printable(inp): + if type(inp) is set: # set of character sequences + return '{' + ', '.join([printable(seq) for seq in inp]) + '}' + if type(inp) is tuple: # character sequence + return '<' + (', '.join([printable(ch) for ch in inp])) + '>' + else: # single character + return 'U+%04X' % inp + + +def open_font(font): font_file, index = font font_path = path.join(_fonts_dir, font_file) if index is not None: - ttfont = ttLib.TTFont(font_path, fontNumber=index) + return ttLib.TTFont(font_path, fontNumber=index) else: - ttfont = ttLib.TTFont(font_path) + return ttLib.TTFont(font_path) + + +def get_best_cmap(font): + ttfont = open_font(font) all_unicode_cmap = None bmp_cmap = None for cmap in ttfont['cmap'].tables: @@ -79,6 +96,52 @@ def get_best_cmap(font): return all_unicode_cmap.cmap if all_unicode_cmap else bmp_cmap.cmap +def get_variation_sequences_cmap(font): + ttfont = open_font(font) + vs_cmap = None + for cmap in ttfont['cmap'].tables: + specifier = (cmap.format, cmap.platformID, cmap.platEncID) + if specifier == (14, 0, 5): + assert vs_cmap is None, 'More than one VS cmap in %s' % (font, ) + vs_cmap = cmap + return vs_cmap + + +def get_emoji_map(font): + # Add normal characters + emoji_map = copy.copy(get_best_cmap(font)) + reverse_cmap = {glyph: code for code, glyph in emoji_map.items()} + + # Add variation sequences + vs_dict = get_variation_sequences_cmap(font).uvsDict + for vs in vs_dict: + for base, glyph in vs_dict[vs]: + if glyph is None: + emoji_map[(base, vs)] = emoji_map[base] + else: + emoji_map[(base, vs)] = glyph + + # Add GSUB rules + ttfont = open_font(font) + for lookup in ttfont['GSUB'].table.LookupList.Lookup: + assert lookup.LookupType == 4, 'We only understand type 4 lookups' + for subtable in lookup.SubTable: + ligatures = subtable.ligatures + for first_glyph in ligatures: + for ligature in ligatures[first_glyph]: + sequence = [first_glyph] + ligature.Component + sequence = [reverse_cmap[glyph] for glyph in sequence] + sequence = tuple(sequence) + # Make sure no starting subsequence of 'sequence' has been + # seen before. + for sub_len in range(2, len(sequence)+1): + subsequence = sequence[:sub_len] + assert subsequence not in emoji_map + emoji_map[sequence] = ligature.LigGlyph + + return emoji_map + + def assert_font_supports_any_of_chars(font, chars): best_cmap = get_best_cmap(font) for char in chars: @@ -101,6 +164,13 @@ def assert_font_supports_none_of_chars(font, chars): 'U+%04X was found in %s' % (char, font)) +def assert_font_supports_all_sequences(font, sequences): + vs_dict = get_variation_sequences_cmap(font).uvsDict + for base, vs in sorted(sequences): + assert vs in vs_dict and (base, None) in vs_dict[vs], ( + '<U+%04X, U+%04X> was not found in %s' % (base, vs, font)) + + def check_hyphens(hyphens_dir): # Find all the scripts that need automatic hyphenation scripts = set() @@ -119,6 +189,16 @@ def check_hyphens(hyphens_dir): assert_font_supports_any_of_chars(font, HYPHENS) +class FontRecord(object): + def __init__(self, name, scripts, variant, weight, style, font): + self.name = name + self.scripts = scripts + self.variant = variant + self.weight = weight + self.style = style + self.font = font + + def parse_fonts_xml(fonts_xml_path): global _script_to_font_map, _fallback_chain _script_to_font_map = collections.defaultdict(set) @@ -159,7 +239,7 @@ def parse_fonts_xml(fonts_xml_path): if index: index = int(index) - _fallback_chain.append(( + _fallback_chain.append(FontRecord( name, frozenset(scripts), variant, @@ -175,39 +255,72 @@ def parse_fonts_xml(fonts_xml_path): _script_to_font_map[script].add((font_file, index)) -def check_emoji_availability(): - emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]] +def check_emoji_coverage(all_emoji, equivalent_emoji): + emoji_fonts = [ + record.font for record in _fallback_chain + if 'Zsye' in record.scripts] assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts) emoji_font = emoji_fonts[0] - emoji_chars = _emoji_properties['Emoji'] - assert_font_supports_all_of_chars(emoji_font, emoji_chars) + coverage = get_emoji_map(emoji_font) + for sequence in all_emoji: + assert sequence in coverage, ( + '%s is not supported in the emoji font.' % printable(sequence)) -def check_emoji_defaults(): - default_emoji_chars = _emoji_properties['Emoji_Presentation'] - missing_text_chars = _emoji_properties['Emoji'] - default_emoji_chars + for sequence in coverage: + if sequence in {0x0000, 0x000D, 0x0020}: + # The font needs to support a few extra characters, which is OK + continue + assert sequence in all_emoji, ( + 'Emoji font should not support %s.' % printable(sequence)) + + for first, second in sorted(equivalent_emoji.items()): + assert coverage[first] == coverage[second], ( + '%s and %s should map to the same glyph.' % ( + printable(first), + printable(second))) + + for glyph in set(coverage.values()): + maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph] + if len(maps_to_glyph) > 1: + # There are more than one sequences mapping to the same glyph. We + # need to make sure they were expected to be equivalent. + equivalent_seqs = set() + for seq in maps_to_glyph: + equivalent_seq = seq + while equivalent_seq in equivalent_emoji: + equivalent_seq = equivalent_emoji[equivalent_seq] + equivalent_seqs.add(equivalent_seq) + assert len(equivalent_seqs) == 1, ( + 'The sequences %s should not result in the same glyph %s' % ( + printable(equivalent_seqs), + glyph)) + + +def check_emoji_defaults(default_emoji): + missing_text_chars = _emoji_properties['Emoji'] - default_emoji emoji_font_seen = False - for name, scripts, variant, weight, style, font in _fallback_chain: - if 'Zsye' in scripts: + for record in _fallback_chain: + if 'Zsye' in record.scripts: emoji_font_seen = True # No need to check the emoji font continue # For later fonts, we only check them if they have a script # defined, since the defined script may get them to a higher # score even if they appear after the emoji font. - if emoji_font_seen and not scripts: + if emoji_font_seen and not record.scripts: continue # Check default emoji-style characters - assert_font_supports_none_of_chars(font, sorted(default_emoji_chars)) + assert_font_supports_none_of_chars(record.font, sorted(default_emoji)) # Mark default text-style characters appearing in fonts above the emoji # font as seen if not emoji_font_seen: - missing_text_chars -= set(get_best_cmap(font)) + missing_text_chars -= set(get_best_cmap(record.font)) - # Noto does not have monochrome symbols for Unicode 7.0 wingdings and - # webdings + # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and + # webdings yet. missing_text_chars -= _chars_by_age['7.0'] # TODO: Remove these after b/26113320 is fixed missing_text_chars -= { @@ -236,31 +349,175 @@ def parse_unicode_datafile(file_path, reverse=False): line = line.strip() if not line: continue - char_range, prop = line.split(';') - char_range = char_range.strip() + + chars, prop = line.split(';') + chars = chars.strip() prop = prop.strip() - if '..' in char_range: - char_start, char_end = char_range.split('..') - else: - char_start = char_end = char_range - char_start = int(char_start, 16) - char_end = int(char_end, 16) - char_range = xrange(char_start, char_end+1) + + if ' ' in chars: # character sequence + sequence = [int(ch, 16) for ch in chars.split(' ')] + additions = [tuple(sequence)] + elif '..' in chars: # character range + char_start, char_end = chars.split('..') + char_start = int(char_start, 16) + char_end = int(char_end, 16) + additions = xrange(char_start, char_end+1) + else: # singe character + additions = [int(chars, 16)] if reverse: - output_dict[prop].update(char_range) + output_dict[prop].update(additions) else: - for char in char_range: - assert char not in output_dict - output_dict[char] = prop + for addition in additions: + assert addition not in output_dict + output_dict[addition] = prop return output_dict +def parse_standardized_variants(file_path): + emoji_set = set() + text_set = set() + with open(file_path) as datafile: + for line in datafile: + if '#' in line: + line = line[:line.index('#')] + line = line.strip() + if not line: + continue + sequence, description, _ = line.split(';') + sequence = sequence.strip().split(' ') + base = int(sequence[0], 16) + vs = int(sequence[1], 16) + description = description.strip() + if description == 'text style': + text_set.add((base, vs)) + elif description == 'emoji style': + emoji_set.add((base, vs)) + return text_set, emoji_set + + def parse_ucd(ucd_path): global _emoji_properties, _chars_by_age + global _text_variation_sequences, _emoji_variation_sequences + global _emoji_sequences, _emoji_zwj_sequences _emoji_properties = parse_unicode_datafile( path.join(ucd_path, 'emoji-data.txt'), reverse=True) _chars_by_age = parse_unicode_datafile( path.join(ucd_path, 'DerivedAge.txt'), reverse=True) + sequences = parse_standardized_variants( + path.join(ucd_path, 'StandardizedVariants.txt')) + _text_variation_sequences, _emoji_variation_sequences = sequences + _emoji_sequences = parse_unicode_datafile( + path.join(ucd_path, 'emoji-sequences.txt')) + _emoji_zwj_sequences = parse_unicode_datafile( + path.join(ucd_path, 'emoji-zwj-sequences.txt')) + + +def flag_sequence(territory_code): + return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code) + + +UNSUPPORTED_FLAGS = frozenset({ + flag_sequence('BL'), flag_sequence('BQ'), flag_sequence('DG'), + flag_sequence('EA'), flag_sequence('EH'), flag_sequence('FK'), + flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'), + flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'), + flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'), + flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'), +}) + +EQUIVALENT_FLAGS = { + flag_sequence('BV'): flag_sequence('NO'), + flag_sequence('CP'): flag_sequence('FR'), + flag_sequence('HM'): flag_sequence('AU'), + flag_sequence('SJ'): flag_sequence('NO'), + flag_sequence('UM'): flag_sequence('US'), +} + +COMBINING_KEYCAP = 0x20E3 + +LEGACY_ANDROID_EMOJI = { + 0xFE4E5: flag_sequence('JP'), + 0xFE4E6: flag_sequence('US'), + 0xFE4E7: flag_sequence('FR'), + 0xFE4E8: flag_sequence('DE'), + 0xFE4E9: flag_sequence('IT'), + 0xFE4EA: flag_sequence('GB'), + 0xFE4EB: flag_sequence('ES'), + 0xFE4EC: flag_sequence('RU'), + 0xFE4ED: flag_sequence('CN'), + 0xFE4EE: flag_sequence('KR'), + 0xFE82C: (ord('#'), COMBINING_KEYCAP), + 0xFE82E: (ord('1'), COMBINING_KEYCAP), + 0xFE82F: (ord('2'), COMBINING_KEYCAP), + 0xFE830: (ord('3'), COMBINING_KEYCAP), + 0xFE831: (ord('4'), COMBINING_KEYCAP), + 0xFE832: (ord('5'), COMBINING_KEYCAP), + 0xFE833: (ord('6'), COMBINING_KEYCAP), + 0xFE834: (ord('7'), COMBINING_KEYCAP), + 0xFE835: (ord('8'), COMBINING_KEYCAP), + 0xFE836: (ord('9'), COMBINING_KEYCAP), + 0xFE837: (ord('0'), COMBINING_KEYCAP), +} + +ZWJ_IDENTICALS = { + # KISS + (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468): 0x1F48F, + # COUPLE WITH HEART + (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F468): 0x1F491, + # FAMILY + (0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F466): 0x1F46A, +} + +def compute_expected_emoji(): + equivalent_emoji = {} + sequence_pieces = set() + all_sequences = set() + all_sequences.update(_emoji_variation_sequences) + + for sequence in _emoji_sequences.keys(): + sequence = tuple(ch for ch in sequence if ch != EMOJI_VS) + all_sequences.add(sequence) + sequence_pieces.update(sequence) + + for sequence in _emoji_zwj_sequences.keys(): + sequence = tuple(ch for ch in sequence if ch != EMOJI_VS) + all_sequences.add(sequence) + sequence_pieces.update(sequence) + # Add reverse of all emoji ZWJ sequences, which are added to the fonts + # as a workaround to get the sequences work in RTL text. + reversed_seq = tuple(reversed(sequence)) + all_sequences.add(reversed_seq) + equivalent_emoji[reversed_seq] = sequence + + # Add all two-letter flag sequences, as even the unsupported ones should + # resolve to a flag tofu. + all_letters = [chr(code) for code in range(ord('A'), ord('Z')+1)] + all_two_letter_codes = itertools.product(all_letters, repeat=2) + all_flags = {flag_sequence(code) for code in all_two_letter_codes} + all_sequences.update(all_flags) + tofu_flags = UNSUPPORTED_FLAGS | (all_flags - set(_emoji_sequences.keys())) + + all_emoji = ( + _emoji_properties['Emoji'] | + all_sequences | + sequence_pieces | + set(LEGACY_ANDROID_EMOJI.keys())) + default_emoji = ( + _emoji_properties['Emoji_Presentation'] | + all_sequences | + set(LEGACY_ANDROID_EMOJI.keys())) + + first_tofu_flag = sorted(tofu_flags)[0] + for flag in tofu_flags: + if flag != first_tofu_flag: + equivalent_emoji[flag] = first_tofu_flag + equivalent_emoji.update(EQUIVALENT_FLAGS) + equivalent_emoji.update(LEGACY_ANDROID_EMOJI) + equivalent_emoji.update(ZWJ_IDENTICALS) + for seq in _emoji_variation_sequences: + equivalent_emoji[seq] = seq[0] + + return all_emoji, default_emoji, equivalent_emoji def main(): @@ -278,8 +535,9 @@ def main(): if check_emoji == 'true': ucd_path = sys.argv[3] parse_ucd(ucd_path) - check_emoji_availability() - check_emoji_defaults() + all_emoji, default_emoji, equivalent_emoji = compute_expected_emoji() + check_emoji_coverage(all_emoji, equivalent_emoji) + check_emoji_defaults(default_emoji) if __name__ == '__main__': diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index 7412bc269c28..50efc7f7db86 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -245,6 +245,13 @@ public class FontFamily_Delegate { return sFontLocation; } + // ---- delegate methods ---- + @LayoutlibDelegate + /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex) { + final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mNativePtr); + return delegate != null && delegate.addFont(path, ttcIndex); + } + // ---- native methods ---- @LayoutlibDelegate @@ -270,16 +277,8 @@ public class FontFamily_Delegate { } @LayoutlibDelegate - /*package*/ static boolean nAddFont(long nativeFamily, final String path, int ttcIndex) { - // FIXME: support ttc fonts. Hack JRE?? - final FontFamily_Delegate delegate = getDelegate(nativeFamily); - if (delegate != null) { - if (sFontLocation == null) { - delegate.mPostInitRunnables.add(() -> delegate.addFont(path)); - return true; - } - return delegate.addFont(path); - } + /*package*/ static boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex) { + assert false : "The only client of this method has been overriden."; return false; } @@ -390,6 +389,15 @@ public class FontFamily_Delegate { mPostInitRunnables = null; } + private boolean addFont(final String path, int ttcIndex) { + // FIXME: support ttc fonts. Hack JRE?? + if (sFontLocation == null) { + mPostInitRunnables.add(() -> addFont(path)); + return true; + } + return addFont(path); + } + private boolean addFont(@NonNull String path) { return addFont(path, DEFAULT_FONT_WEIGHT, path.endsWith(FONT_SUFFIX_ITALIC)); } diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java index d8ff57bf0b7a..7fa7235ab881 100644 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java @@ -90,7 +90,7 @@ public class VectorDrawable_Delegate { } @LayoutlibDelegate - static long nCreateRenderer(long rootGroupPtr) { + static long nCreateTree(long rootGroupPtr) { VGroup_Delegate rootGroup = VNativeObject.getDelegate(rootGroupPtr); return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup)); } diff --git a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java index 6c34c70b7609..6d3bb4ca9115 100644 --- a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java +++ b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java @@ -64,15 +64,14 @@ public class PathParser_Delegate { } @LayoutlibDelegate - /*package*/ static boolean nParseStringForPath(long pathPtr, @NonNull String pathString, int + /*package*/ static void nParseStringForPath(long pathPtr, @NonNull String pathString, int stringLength) { Path_Delegate path_delegate = Path_Delegate.getDelegate(pathPtr); if (path_delegate == null) { - return false; + return; } assert pathString.length() == stringLength; PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate); - return true; } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 9e50ee898769..3b882909698d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -537,7 +537,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { * Note that while this can be called several time, the first call to {@link #cleanupThread()} * will do the clean-up, and make the thread unable to do further scene actions. */ - public static void prepareThread() { + public synchronized static void prepareThread() { // we need to make sure the Looper has been initialized for this thread. // this is required for View that creates Handler objects. if (Looper.myLooper() == null) { @@ -551,7 +551,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single * call to this will prevent the thread from doing further scene actions */ - public static void cleanupThread() { + public synchronized static void cleanupThread() { // clean up the looper Looper_Accessor.cleanupThread(); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java index fea633e7036d..308488a39ec7 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java @@ -70,23 +70,6 @@ public class BridgeRenderSession extends RenderSession { } @Override - public Map<String, String> getDefaultProperties(Object viewObject) { - return mSession.getDefaultProperties(viewObject); - } - - @Override - public Result getProperty(Object objectView, String propertyName) { - // pass - return super.getProperty(objectView, propertyName); - } - - @Override - public Result setProperty(Object objectView, String propertyName, String propertyValue) { - // pass - return super.setProperty(objectView, propertyName, propertyValue); - } - - @Override public Result render(long timeout, boolean forceMeasure) { try { Bridge.prepareThread(); @@ -213,6 +196,10 @@ public class BridgeRenderSession extends RenderSession { } } + public RenderSessionImpl getSessionImpl() { + return mSession; + } + /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) { mSession = scene; if (scene != null) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 89272fa916c1..fd95bd5a0204 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -27,6 +27,7 @@ import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.StyleResourceValue; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; +import com.android.layoutlib.bridge.android.PropertiesMap.Property; import com.android.layoutlib.bridge.android.view.WindowManagerImpl; import com.android.layoutlib.bridge.impl.ParserFactory; import com.android.layoutlib.bridge.impl.Stack; @@ -275,7 +276,7 @@ public final class BridgeContext extends Context { return mRenderResources; } - public Map<String, String> getDefaultPropMap(Object key) { + public PropertiesMap getDefaultPropMap(Object key) { return mDefaultPropMaps.get(key); } @@ -731,16 +732,10 @@ public final class BridgeContext extends Context { Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE, "Failed to find the style corresponding to the id " + defStyleAttr, null); } else { - if (defaultPropMap != null) { - String defStyleName = defStyleAttribute.getFirst(); - if (defStyleAttribute.getSecond()) { - defStyleName = "android:" + defStyleName; - } - defaultPropMap.put("style", defStyleName); - } + String defStyleName = defStyleAttribute.getFirst(); // look for the style in the current theme, and its parent: - ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(), + ResourceValue item = mRenderResources.findItemInTheme(defStyleName, defStyleAttribute.getSecond()); if (item != null) { @@ -750,6 +745,12 @@ public final class BridgeContext extends Context { if (item instanceof StyleResourceValue) { defStyleValues = (StyleResourceValue) item; } + if (defaultPropMap != null) { + if (defStyleAttribute.getSecond()) { + defStyleName = "android:" + defStyleName; + } + defaultPropMap.put("style", new Property(defStyleName, item.getValue())); + } } else { Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR, String.format( @@ -776,7 +777,8 @@ public final class BridgeContext extends Context { item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes); if (item != null) { if (defaultPropMap != null) { - defaultPropMap.put("style", item.getName()); + String name = item.getName(); + defaultPropMap.put("style", new Property(name, name)); } defStyleValues = item; @@ -855,13 +857,14 @@ public final class BridgeContext extends Context { // if we found a value, we make sure this doesn't reference another value. // So we resolve it. if (resValue != null) { - // put the first default value, before the resolution. + String preResolve = resValue.getValue(); + resValue = mRenderResources.resolveResValue(resValue); + if (defaultPropMap != null) { - defaultPropMap.put(attrName, resValue.getValue()); + defaultPropMap.put(attrName, + new Property(preResolve, resValue.getValue())); } - resValue = mRenderResources.resolveResValue(resValue); - // If the value is a reference to another theme attribute that doesn't // exist, we should log a warning and omit it. String val = resValue.getValue(); @@ -949,10 +952,11 @@ public final class BridgeContext extends Context { if (resValue != null) { // Add it to defaultPropMap before resolving - defaultPropMap.put(attrName, resValue.getValue()); + String preResolve = resValue.getValue(); // resolve it to make sure there are no references left. - ta.bridgeSetValue(i, attrName, attribute.getSecond(), - mRenderResources.resolveResValue(resValue)); + resValue = mRenderResources.resolveResValue(resValue); + ta.bridgeSetValue(i, attrName, attribute.getSecond(), resValue); + defaultPropMap.put(attrName, new Property(preResolve, resValue.getValue())); } } } @@ -1915,11 +1919,4 @@ public final class BridgeContext extends Context { } } - - /** - * An alias used for the value in {@code {@link #mDefaultPropMaps}} - */ - private static class PropertiesMap extends HashMap<String, String> { - } - } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index 42c0ae0d8d8f..0a64b63bfc64 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -645,6 +645,11 @@ public class BridgePackageManager extends PackageManager { } @Override + public void deleteApplicationCacheFilesAsUser(String packageName, int userId, + IPackageDataObserver observer) { + } + + @Override public void freeStorageAndNotify(String volumeUuid, long freeStorageSize, IPackageDataObserver observer) { } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java new file mode 100644 index 000000000000..a38d579d2b4b --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package com.android.layoutlib.bridge.android; + +import com.android.layoutlib.bridge.android.PropertiesMap.Property; + +import java.util.HashMap; + +/** + * An alias used for the value in {@link BridgeContext#mDefaultPropMaps} + */ +public class PropertiesMap extends HashMap<String, Property> { + + public static class Property { + public final String resource; + public final String value; + + public Property(String resource, String value) { + this.resource = resource; + this.value = value; + } + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 0c537533479e..2d388312330b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -286,7 +286,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso return mParams; } - protected BridgeContext getContext() { + public BridgeContext getContext() { return mContext; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 866b2480b828..11fabc6a59a9 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -1415,10 +1415,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { return mSystemViewInfoList; } - public Map<String, String> getDefaultProperties(Object viewObject) { - return getContext().getDefaultPropMap(viewObject); - } - public void setScene(RenderSession session) { mScene = session; } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 483bddc21859..061bed7b7740 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -192,6 +192,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.BitmapFactory#setDensityFromOptions", "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget", "android.graphics.drawable.GradientDrawable#buildRing", + "android.graphics.FontFamily#addFont", "android.graphics.Typeface#getSystemFontConfigLocation", "android.graphics.Typeface#makeFamilyFromParsed", "android.os.Handler#sendMessageAtTime", |