diff options
125 files changed, 3343 insertions, 648 deletions
diff --git a/api/current.txt b/api/current.txt index 7d762fee6dcb..5dfb0053983e 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); } @@ -9497,7 +9497,6 @@ 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); @@ -29584,6 +29583,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 +49061,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 +49932,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 +57593,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[]); @@ -58627,6 +58634,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[]); @@ -60144,18 +60163,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); @@ -61528,6 +61535,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(); @@ -61537,6 +61545,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 362fa3f49e91..3febd2915acc 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); } @@ -9835,7 +9835,6 @@ 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); @@ -31890,6 +31889,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 +52174,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 +53045,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 +60706,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[]); @@ -61740,6 +61747,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[]); @@ -63257,18 +63276,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); @@ -64641,6 +64648,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(); @@ -64650,6 +64658,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 8ee165521cb3..7805613d291a 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); } @@ -9507,7 +9507,6 @@ 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); @@ -29653,6 +29652,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 +49139,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 +50010,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 +57671,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[]); @@ -58705,6 +58712,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[]); @@ -60222,18 +60241,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); @@ -61606,6 +61613,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(); @@ -61615,6 +61623,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/Notification.java b/core/java/android/app/Notification.java index 784872cedaa2..520acf502f0d 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); } @@ -3749,6 +3762,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 +4392,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.applyStandardTemplate( + 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/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/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..7c2d4aac6947 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -291,7 +291,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 +301,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 +311,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 +385,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) { 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/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..da215c61641a 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) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 638be5167f86..fdb1cef60152 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1581,6 +1581,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 +2091,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))); 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/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/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index f2bf9e1d9695..1f2acc9d5489 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -760,7 +760,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/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/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..03d21929dd01 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" /> @@ -2496,6 +2494,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 +2525,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/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/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/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/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/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/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 7ca76141a84c..796dff52304d 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 @@ -1165,6 +1182,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/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/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/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/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/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java index 13e1a14ead63..e7e81d62340f 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(); @@ -494,12 +495,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/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..46e77802ceb1 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 @@ -189,6 +189,7 @@ public class TaskCardView extends LinearLayout { } public void startDismissTaskAnimation(Animator.AnimatorListener listener) { + mDismissState = false; mDismissAnimationsHolder.startDismissAnimation(listener); } @@ -201,4 +202,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/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/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 98e0dd96ee75..8461d8e75b34 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -133,6 +133,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; @@ -445,6 +447,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDockSide = WindowManager.DOCKED_INVALID; mCurrentAnimator = null; mEntranceAnimationRunning = false; + mExitAnimationRunning = false; EventBus.getDefault().send(new StoppedDragingEvent()); } }); @@ -654,6 +657,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 +905,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/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 1b2393afcccf..3ac7b26a9968 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() { @@ -2353,6 +2376,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/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/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 75430ffe2d0a..f68b24bb3316 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1374,6 +1374,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 +3595,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/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/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/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/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/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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2765578a7c3d..9a5988c5aaf5 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; @@ -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/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/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java index cd976e753a0a..df5d0274c20a 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); } @@ -497,8 +499,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/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 446b74bc1933..1475686cca47 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -910,7 +910,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/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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e7ae2b0fcfd5..6f45508d0d24 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -823,7 +823,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"); 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/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/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/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/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/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/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", |