Merge "Use session id to uniquely identidy autofill ids for multi-session."
diff --git a/api/current.txt b/api/current.txt
index d3ef74f..e31f8a0 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -5680,6 +5680,7 @@
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
method public boolean areNotificationsEnabled();
+ method public boolean canNotifyAsPackage(java.lang.String);
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5698,13 +5699,17 @@
method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
+ method public java.lang.String getNotificationDelegate();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
+ method public void notifyAsPackage(java.lang.String, java.lang.String, int, android.app.Notification);
method public boolean removeAutomaticZenRule(java.lang.String);
+ method public void revokeNotificationDelegate();
method public final void setInterruptionFilter(int);
+ method public void setNotificationDelegate(java.lang.String);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
@@ -13978,6 +13983,7 @@
method public float getFontSpacing();
method public java.lang.String getFontVariationSettings();
method public int getHinting();
+ method public int getHyphenEdit();
method public float getLetterSpacing();
method public android.graphics.MaskFilter getMaskFilter();
method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
@@ -14041,6 +14047,7 @@
method public void setFontFeatureSettings(java.lang.String);
method public boolean setFontVariationSettings(java.lang.String);
method public void setHinting(int);
+ method public void setHyphenEdit(int);
method public void setLetterSpacing(float);
method public void setLinearText(boolean);
method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
@@ -15237,7 +15244,9 @@
field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320
field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8
field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c
+ field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8
field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4
+ field public static final int FONT_WEIGHT_MIN = 1; // 0x1
field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258
field public static final int FONT_WEIGHT_THIN = 100; // 0x64
@@ -39652,10 +39661,12 @@
method public int getId();
method public java.lang.String getKey();
method public android.app.Notification getNotification();
+ method public java.lang.String getOpPkg();
method public java.lang.String getOverrideGroupKey();
method public java.lang.String getPackageName();
method public long getPostTime();
method public java.lang.String getTag();
+ method public int getUid();
method public android.os.UserHandle getUser();
method public deprecated int getUserId();
method public boolean isClearable();
@@ -43497,6 +43508,22 @@
method public abstract void handleTag(boolean, java.lang.String, android.text.Editable, org.xml.sax.XMLReader);
}
+ public class Hyphenator {
+ method public static int packHyphenEdit(int, int);
+ method public static int unpackEndHyphenEdit(int);
+ method public static int unpackStartHyphenEdit(int);
+ field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3
+ field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2
+ field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4
+ field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5
+ field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6
+ field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
+ field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1
+ field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1
+ field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2
+ field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
+ }
+
public abstract interface InputFilter {
method public abstract java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3171e3e..4f004d93 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -165,4 +165,9 @@
void applyRestore(in byte[] payload, int user);
ParceledListSlice getAppActiveNotifications(String callingPkg, int userId);
+
+ void setNotificationDelegate(String callingPkg, String delegate);
+ void revokeNotificationDelegate(String callingPkg);
+ String getNotificationDelegate(String callingPkg);
+ boolean canNotifyAsPackage(String callingPkg, String targetPkg);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 4b25b8b..b96b39d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -352,7 +353,7 @@
}
/**
- * Post a notification to be shown in the status bar. If a notification with
+ * Posts a notification to be shown in the status bar. If a notification with
* the same tag and id has already been posted by your application and has not yet been
* canceled, it will be replaced by the updated information.
*
@@ -376,6 +377,42 @@
}
/**
+ * Posts a notification as a specified package to be shown in the status bar. If a notification
+ * with the same tag and id has already been posted for that package and has not yet been
+ * canceled, it will be replaced by the updated information.
+ *
+ * All {@link android.service.notification.NotificationListenerService listener services} will
+ * be granted {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} access to any {@link Uri uris}
+ * provided on this notification or the
+ * {@link NotificationChannel} this notification is posted to using
+ * {@link Context#grantUriPermission(String, Uri, int)}. Permission will be revoked when the
+ * notification is canceled, or you can revoke permissions with
+ * {@link Context#revokeUriPermission(Uri, int)}.
+ *
+ * @param targetPackage The package to post the notification as. The package must have granted
+ * you access to post notifications on their behalf with
+ * {@link #setNotificationDelegate(String)}.
+ * @param tag A string identifier for this notification. May be {@code null}.
+ * @param id An identifier for this notification. The pair (tag, id) must be unique
+ * within your application.
+ * @param notification A {@link Notification} object describing what to
+ * show the user. Must not be null.
+ */
+ public void notifyAsPackage(@NonNull String targetPackage, @NonNull String tag, int id,
+ Notification notification) {
+ INotificationManager service = getService();
+ String sender = mContext.getPackageName();
+
+ try {
+ if (localLOGV) Log.v(TAG, sender + ": notify(" + id + ", " + notification + ")");
+ service.enqueueNotificationWithTag(targetPackage, sender, tag, id,
+ fixNotification(notification), mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -383,6 +420,18 @@
{
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+
+ try {
+ if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
+ service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
+ fixNotification(notification), user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private Notification fixNotification(Notification notification) {
+ String pkg = mContext.getPackageName();
// Fix the notification as best we can.
Notification.addFieldsFromContext(mContext, notification);
@@ -400,19 +449,12 @@
+ notification);
}
}
- if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
+
notification.reduceImageSizes(mContext);
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
boolean isLowRam = am.isLowRamDevice();
- final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam,
- mContext);
- try {
- service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- copy, user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return Builder.maybeCloneStrippedForDelivery(notification, isLowRam, mContext);
}
private void fixLegacySmallIcon(Notification n, String pkg) {
@@ -474,6 +516,72 @@
}
/**
+ * Allows a package to post notifications on your behalf using
+ * {@link #notifyAsPackage(String, String, int, Notification)}.
+ *
+ * This can be used to allow persistent processes to post notifications based on messages
+ * received on your behalf from the cloud, without your process having to wake up.
+ *
+ * You can check if you have an allowed delegate with {@link #getNotificationDelegate()} and
+ * revoke your delegate with {@link #revokeNotificationDelegate()}.
+ *
+ * @param delegate Package name of the app which can send notifications on your behalf.
+ */
+ public void setNotificationDelegate(@NonNull String delegate) {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
+ try {
+ service.setNotificationDelegate(pkg, delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Revokes permission for your {@link #setNotificationDelegate(String) notification delegate}
+ * to post notifications on your behalf.
+ */
+ public void revokeNotificationDelegate() {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ try {
+ service.revokeNotificationDelegate(pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the {@link #setNotificationDelegate(String) delegate} that can post notifications on
+ * your behalf, if there currently is one.
+ */
+ public @Nullable String getNotificationDelegate() {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ try {
+ return service.getNotificationDelegate(pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether you are allowed to post notifications on behalf of a given package, with
+ * {@link #notifyAsPackage(String, String, int, Notification)}.
+ *
+ * See {@link #setNotificationDelegate(String)}.
+ */
+ public boolean canNotifyAsPackage(String pkg) {
+ INotificationManager service = getService();
+ try {
+ return service.canNotifyAsPackage(mContext.getPackageName(), pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a group container for {@link NotificationChannel} objects.
*
* This can be used to rename an existing group.
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index dd97d52..84826e0 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -18,7 +18,7 @@
import android.annotation.UnsupportedAppUsage;
import android.app.Notification;
-import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -261,7 +261,7 @@
return this.user.getIdentifier();
}
- /** The package of the app that posted the notification. */
+ /** The package that the notification belongs to. */
public String getPackageName() {
return pkg;
}
@@ -277,14 +277,18 @@
return tag;
}
- /** The notifying app's calling uid. @hide */
- @UnsupportedAppUsage
+ /**
+ * The notifying app's ({@link #getPackageName()}'s) uid.
+ */
public int getUid() {
return uid;
}
- /** The package used for AppOps tracking. @hide */
- @UnsupportedAppUsage
+ /** The package that posted the notification.
+ *<p>
+ * Might be different from {@link #getPackageName()} if the app owning the notification has
+ * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
+ */
public String getOpPkg() {
return opPkg;
}
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 4f1488e..e4200ac 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -16,15 +16,145 @@
package android.text;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
- * Hyphenator just initializes the native implementation of automatic hyphenation,
- * in essence finding valid hyphenation opportunities in a word.
+ * Provides constants and pack/unpack methods for the HyphenEdit.
*
- * @hide
+ * Hyphenator provides constant values for start of line and end of line modification.
+ * For example, by passing {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+ * character is appended at the end of line.
+ *
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * paint.setHyphenEdit(Hyphenator.packHyphenEdit(
+ * Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+ * paint.measureText("abc", 0, 3); // Returns the width of "abc‐"
+ * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐"
+ * </code>
+ * </pre>
+ *
+ * @see android.graphics.Paint#setHyphenEdit(int)
*/
public class Hyphenator {
+ private Hyphenator() {}
+
+ /** @hide */
+ @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = {
+ START_HYPHEN_EDIT_NO_EDIT,
+ START_HYPHEN_EDIT_INSERT_HYPHEN,
+ START_HYPHEN_EDIT_INSERT_ZWJ
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartHyphenEdit {}
+
+ /**
+ * An integer representing the starting of the line has no modification for hyphenation.
+ */
+ public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+ /**
+ * An integer representing the starting of the line has normal hyphen character (U+002D).
+ */
+ public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01;
+
+ /**
+ * An integer representing the starting of the line has Zero-Width-Joiner (U+200D).
+ */
+ public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02;
+
+ /** @hide */
+ @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = {
+ END_HYPHEN_EDIT_NO_EDIT,
+ END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_MAQAF,
+ END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EndHyphenEdit {}
+
+ /**
+ * An integer representing the end of the line has no modification for hyphenation.
+ */
+ public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+ /**
+ * An integer representing the character at the end of the line is replaced with hyphen
+ * character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01;
+
+ /**
+ * An integer representing the end of the line has normal hyphen character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02;
+
+ /**
+ * An integer representing the end of the line has Armentian hyphen (U+058A).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03;
+
+ /**
+ * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04;
+
+ /**
+ * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05;
+
+ /**
+ * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal
+ * hyphen character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06;
+
+ // Following three constants are used for packing start hyphen edit and end hyphen edit into
+ // single integer. Following encodings must be the same as the minikin's one.
+ // See frameworks/minikin/include/Hyphenator.h for more details.
+ private static final int END_HYPHEN_EDIT_MASK = 0x07; // 0b00111
+ private static final int START_HYPHEN_EDIT_MASK = 0x18; // 0b11000
+ private static final int START_HYPHEN_EDIT_SHIFT = 0x03;
+
+ /**
+ * Extract start hyphen edit from packed value.
+ */
+ public static @StartHyphenEdit int unpackStartHyphenEdit(int hyphenEdit) {
+ return (hyphenEdit & START_HYPHEN_EDIT_MASK) >> START_HYPHEN_EDIT_SHIFT;
+ }
+
+ /**
+ * Extract end hyphen edit from packed value.
+ */
+ public static @EndHyphenEdit int unpackEndHyphenEdit(int hyphenEdit) {
+ return hyphenEdit & END_HYPHEN_EDIT_MASK;
+ }
+
+ /**
+ * Pack the start hyphen edit and end hyphen edit into single integer.
+ */
+ public static int packHyphenEdit(@StartHyphenEdit int startHyphenEdit,
+ @EndHyphenEdit int endHyphenEdit) {
+ return ((startHyphenEdit << START_HYPHEN_EDIT_SHIFT) & START_HYPHEN_EDIT_MASK)
+ | (endHyphenEdit & END_HYPHEN_EDIT_MASK);
+ }
+
+
+ /**
+ * @hide
+ */
public static void init() {
nInit();
}
+
private static native void nInit();
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 128f860..5adb1ca 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1216,11 +1216,19 @@
}
/**
+ * Returns the packed hyphen edit value for this line.
+ *
+ * You can extract start hyphen edit and end hyphen edit by using
+ * {@link Hyphenator#unpackStartHyphenEdit(int)} and
+ * {@link Hyphenator#unpackEndHyphenEdit(int)}.
+ *
+ * @param lineNumber a line number
+ * @return A packed hyphen edit value.
* @hide
*/
@Override
- public int getHyphen(int line) {
- return mLines[mColumns * line + HYPHEN] & HYPHEN_MASK;
+ public int getHyphen(int lineNumber) {
+ return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK;
}
/**
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 9667b10..bf2d600 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -1053,13 +1053,16 @@
return runIsRtl ? -ret : ret;
}
- private int adjustHyphenEdit(int start, int limit, int hyphenEdit) {
- int result = hyphenEdit;
+ private int adjustHyphenEdit(int start, int limit, int packedHyphenEdit) {
+ int result = packedHyphenEdit;
// Only draw hyphens on first or last run in line. Disable them otherwise.
if (start > 0) { // not the first run
- result &= ~Paint.HYPHENEDIT_MASK_START_OF_LINE;
+ result = Hyphenator.packHyphenEdit(Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ Hyphenator.unpackEndHyphenEdit(packedHyphenEdit));
}
if (limit < mLen) { // not the last run
+ result = Hyphenator.packHyphenEdit(Hyphenator.unpackStartHyphenEdit(packedHyphenEdit),
+ Hyphenator.END_HYPHEN_EDIT_NO_EDIT);
result &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE;
}
return result;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1b412a7..0645a16 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -63,6 +63,7 @@
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.graphics.fonts.Font;
import android.graphics.fonts.FontVariationAxis;
import android.icu.text.DecimalFormatSymbols;
import android.os.AsyncTask;
@@ -2068,7 +2069,7 @@
*/
private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName,
@XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style,
- @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) {
if (typeface == null && familyName != null) {
// Lookup normal Typeface from system font map.
final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
@@ -2095,9 +2096,9 @@
}
private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style,
- @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) {
if (weight >= 0) {
- weight = Math.min(Typeface.MAX_WEIGHT, weight);
+ weight = Math.min(Font.FONT_WEIGHT_MAX, weight);
final boolean italic = (style & Typeface.ITALIC) != 0;
setTypeface(Typeface.create(typeface, weight, italic));
} else {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7fc1787..6f30653 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1742,26 +1742,52 @@
}
/**
- * Get the current value of hyphen edit.
+ * Get the current value of packed hyphen edit.
+ *
+ * You can extract start hyphen edit and end hyphen edit by using
+ * {@link android.text.Hyphenator#unpackStartHyphenEdit(int)} and
+ * {@link android.text.Hyphenator#unpackEndHyphenEdit(int)}.
+ *
+ * The default value is 0 which is equivalent to packed value of
+ * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
*
* @return the current hyphen edit value
- *
- * @hide
+ * @see #setHyphenEdit(int)
*/
public int getHyphenEdit() {
return nGetHyphenEdit(mNativePaint);
}
/**
- * Set a hyphen edit on the paint (causes a hyphen to be added to text when
- * measured or drawn).
+ * Set a packed hyphen edit on the paint.
*
- * @param hyphen 0 for no edit, 1 for adding a hyphen at the end, etc.
- * Definition of various values are in the HyphenEdit class in Minikin's Hyphenator.h.
+ * By setting hyphen edit, the measurement and drawing is performed with modifying hyphenation
+ * at the start of line and end of line. For example, by passing
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+ * character is appended at the end of line.
*
- * @hide
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * paint.setHyphenEdit(Hyphenator.packHyphenEdit(
+ * Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+ * paint.measureText("abc", 0, 3); // Returns the width of "abc‐"
+ * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐"
+ * </code>
+ * </pre>
+ *
+ * You can pack start hyphen edit and end hyphen edit by
+ * {@link android.text.Hyphenator#packHyphenEdit(int,int)}
+ *
+ * The default value is 0 which is equivalent to packed value of
+ * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
+ *
+ * @param hyphen a packed hyphen edit value.
+ * @see #getHyphenEdit()
*/
- @UnsupportedAppUsage
public void setHyphenEdit(int hyphen) {
nSetHyphenEdit(mNativePaint, hyphen);
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 4388411..5aa09ce 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -148,13 +148,7 @@
@UnsupportedAppUsage
private @Style int mStyle = 0;
- /**
- * A maximum value for the weight value.
- * @hide
- */
- public static final int MAX_WEIGHT = 1000;
-
- private @IntRange(from = 0, to = MAX_WEIGHT) int mWeight = 0;
+ private @IntRange(from = 0, to = android.graphics.fonts.Font.FONT_WEIGHT_MAX) int mWeight = 0;
// Value for weight and italic. Indicates the value is resolved by font metadata.
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index a99d297..8aa4845 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -51,6 +51,11 @@
private static final int STYLE_NORMAL = 0;
/**
+ * A minimum weight value for the font
+ */
+ public static final int FONT_WEIGHT_MIN = 1;
+
+ /**
* A font weight value for the thin weight
*/
public static final int FONT_WEIGHT_THIN = 100;
@@ -96,6 +101,11 @@
public static final int FONT_WEIGHT_BLACK = 900;
/**
+ * A maximum weight value for the font
+ */
+ public static final int FONT_WEIGHT_MAX = 1000;
+
+ /**
* A builder class for creating new Font.
*/
public static class Builder {
@@ -322,8 +332,9 @@
* @param weight a weight value
* @return this builder
*/
- public @NonNull Builder setWeight(@IntRange(from = 1, to = 1000) int weight) {
- Preconditions.checkArgument(1 <= weight && weight <= 1000);
+ public @NonNull Builder setWeight(
+ @IntRange(from = FONT_WEIGHT_MIN, to = FONT_WEIGHT_MAX) int weight) {
+ Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX);
mWeight = weight;
return this;
}
@@ -403,6 +414,7 @@
mItalic = STYLE_NORMAL;
}
}
+ mWeight = Math.max(FONT_WEIGHT_MIN, Math.min(FONT_WEIGHT_MAX, mWeight));
final boolean italic = (mItalic == STYLE_ITALIC);
final long builderPtr = nInitBuilder();
if (mAxes != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 689669f..caea04f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -32,11 +32,10 @@
import java.util.List;
/**
- * MapProfile handles Bluetooth MAP profile.
+ * MapProfile handles the Bluetooth MAP MSE role
*/
public class MapProfile implements LocalBluetoothProfile {
private static final String TAG = "MapProfile";
- private static boolean V = true;
private BluetoothMap mService;
private boolean mIsProfileReady;
@@ -59,7 +58,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected");
mService = (BluetoothMap) proxy;
// We just bound to the service, so refresh the UI for any connected MAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,14 +80,14 @@
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected");
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
}
public boolean isProfileReady() {
- if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+ Log.d(TAG, "isProfileReady(): " + mIsProfileReady);
return mIsProfileReady;
}
@@ -114,45 +113,45 @@
}
public boolean connect(BluetoothDevice device) {
- if(V)Log.d(TAG,"connect() - should not get called");
+ Log.d(TAG, "connect() - should not get called");
return false; // MAP never connects out
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- return mService.disconnect(device);
- } else {
+ if (mService == null) {
return false;
}
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
}
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device));
-
- return !deviceList.isEmpty() && deviceList.get(0).equals(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -163,7 +162,9 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -201,7 +202,7 @@
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index ed06752..304a00f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -495,32 +495,37 @@
}
@Override
- public void onUserSwitched(int newUserId) {
- super.onUserSwitched(newUserId);
- if (mFullscreenUserSwitcher != null) {
- mFullscreenUserSwitcher.onUserSwitched(newUserId);
- }
- }
-
- @Override
public void onStateChanged(int newState) {
super.onStateChanged(newState);
- CarUserManagerHelper helper = new CarUserManagerHelper(mContext);
- if (!helper.isHeadlessSystemUser()) {
- showUserSwitcher();
+ if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ if (!mFullscreenUserSwitcher.isVisible()) {
+ // Current execution path continues to set state after this, thus we deffer the
+ // dismissal to the next execution cycle.
+ postDismissKeyguard(); // Dismiss the keyguard if switcher is not visible.
+ }
+ } else {
+ mFullscreenUserSwitcher.hide();
}
}
public void showUserSwitcher() {
- if (mFullscreenUserSwitcher != null) {
- if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
- mFullscreenUserSwitcher.show();
- } else {
- mFullscreenUserSwitcher.hide();
- }
+ if (mFullscreenUserSwitcher != null && mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ mFullscreenUserSwitcher.show(); // Makes the switcher visible.
}
}
+ public void postDismissKeyguard() {
+ mHandler.post(this::dismissKeyguard);
+ }
+
+ /**
+ * Dismisses the keyguard and shows bouncer if authentication is necessary.
+ */
+ public void dismissKeyguard() {
+ executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ }
+
@Override
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
// Do nothing, we don't want to display media art in the lock screen for a car.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 67a76fd..2ebf5eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.car.user.CarUserManagerHelper;
import android.content.Context;
import android.view.View;
import android.view.ViewStub;
@@ -26,115 +25,87 @@
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.StatusBar;
/**
* Manages the fullscreen user switcher.
*/
public class FullscreenUserSwitcher {
- private final View mContainer;
- private final View mParent;
private final UserGridRecyclerView mUserGridView;
+ private final View mParent;
private final int mShortAnimDuration;
- private final StatusBar mStatusBar;
- private final CarUserManagerHelper mCarUserManagerHelper;
- private boolean mShowing;
+ private final CarStatusBar mStatusBar;
- public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) {
+ public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
mStatusBar = statusBar;
mParent = containerStub.inflate();
- mContainer = mParent.findViewById(R.id.container);
- mUserGridView = mContainer.findViewById(R.id.user_grid);
+ mParent.setVisibility(View.VISIBLE);
+ View container = mParent.findViewById(R.id.container);
+
+ // Initialize user grid.
+ mUserGridView = container.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
- context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
- mCarUserManagerHelper = new CarUserManagerHelper(context);
+ // Hide the user grid by default. It will only be made visible by clicking on a cancel
+ // button in a bouncer.
+ hide();
- mShortAnimDuration = mContainer.getResources()
+ mShortAnimDuration = container.getResources()
.getInteger(android.R.integer.config_shortAnimTime);
}
+ /**
+ * Makes user grid visible.
+ */
public void show() {
- if (mCarUserManagerHelper.isHeadlessSystemUser()) {
- showUserGrid();
- }
- if (mShowing) {
- return;
- }
- mShowing = true;
- mParent.setVisibility(View.VISIBLE);
- }
-
- public void hide() {
- mShowing = false;
- mParent.setVisibility(View.GONE);
- }
-
- public void onUserSwitched(int newUserId) {
- toggleSwitchInProgress(false);
- mParent.post(this::dismissKeyguard);
- }
-
- private void onUserSelected(UserGridRecyclerView.UserRecord record) {
- if (mCarUserManagerHelper.isHeadlessSystemUser()) {
- hideUserGrid();
- }
-
- if (record.mIsForeground || (record.mIsStartGuestSession
- && mCarUserManagerHelper.isForegroundUserGuest())) {
- dismissKeyguard();
- return;
- }
- toggleSwitchInProgress(true);
- }
-
- private void showUserGrid() {
mUserGridView.setVisibility(View.VISIBLE);
}
- private void hideUserGrid() {
+ /**
+ * Hides the user grid.
+ */
+ public void hide() {
mUserGridView.setVisibility(View.INVISIBLE);
}
- // Dismisses the keyguard and shows bouncer if authentication is necessary.
- private void dismissKeyguard() {
- mStatusBar.executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
- true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ /**
+ * @return {@code true} if user grid is visible, {@code false} otherwise.
+ */
+ public boolean isVisible() {
+ return mUserGridView.getVisibility() == View.VISIBLE;
}
- private void toggleSwitchInProgress(boolean inProgress) {
- if (inProgress) {
- fadeOut(mContainer);
- } else {
- fadeIn(mContainer);
+ /**
+ * Every time user clicks on an item in the switcher, we hide the switcher, either
+ * gradually or immediately.
+ *
+ * We dismiss the entire keyguard if user clicked on the foreground user (user we're already
+ * logged in as).
+ */
+ private void onUserSelected(UserGridRecyclerView.UserRecord record) {
+ if (record.mIsForeground) {
+ hide();
+ mStatusBar.dismissKeyguard();
+ return;
}
+ // Switching is about to happen, since it takes time, fade out the switcher gradually.
+ fadeOut();
}
- private void fadeOut(View view) {
- view.animate()
+ private void fadeOut() {
+ mUserGridView.animate()
.alpha(0.0f)
.setDuration(mShortAnimDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- view.setVisibility(View.GONE);
+ hide();
+ mUserGridView.setAlpha(1.0f);
}
});
- }
- private void fadeIn(View view) {
- view.animate()
- .alpha(1.0f)
- .setDuration(mShortAnimDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- view.setAlpha(0.0f);
- view.setVisibility(View.VISIBLE);
- }
- });
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
new file mode 100644
index 0000000..f204c42
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation;
+
+@Retention(RetentionPolicy.SOURCE)
+public @interface ShadeViewRefactor {
+ /**
+ * Returns the refactor component.
+ * @return the refactor component.
+ */
+ RefactorComponent value();
+
+ public enum RefactorComponent {
+ ADAPTER,
+ LAYOUT_ALGORITHM,
+ STATE_RESOLVER,
+ DECORATOR,
+ INPUT,
+ COORDINATOR,
+ SHADE_VIEW
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1883aa7..52844fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -134,6 +134,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.ShadeViewRefactor;
+import java.lang.annotation.ShadeViewRefactor.RefactorComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -465,18 +467,22 @@
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelView mNotificationPanel;
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context) {
this(context, null);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -524,6 +530,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onFinishInflate() {
super.onFinishInflate();
@@ -534,6 +541,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onDensityOrFontScaleChanged() {
inflateFooterView();
inflateEmptyShadeView();
@@ -541,6 +549,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onThemeChanged() {
int which;
if (mStatusBarState == StatusBarState.KEYGUARD
@@ -557,6 +566,7 @@
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
boolean showFooterView = (showDismissView ||
@@ -570,6 +580,7 @@
/**
* Return whether there are any clearable notifications
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasActiveClearableNotifications() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -584,7 +595,8 @@
return false;
}
- public RemoteInputController.Delegate createDelegate() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationData.Entry entry,
boolean remoteInputActive) {
@@ -605,6 +617,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class).addListener(mStateListener);
@@ -612,6 +625,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
@@ -619,11 +633,13 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuClicked(View view, int x, int y, MenuItem item) {
if (mLongPressListener == null) {
return;
@@ -637,6 +653,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuReset(View row) {
if (mTranslatingParentView != null && row == mTranslatingParentView) {
mMenuExposedView = null;
@@ -645,6 +662,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuShown(View row) {
mMenuExposedView = mTranslatingParentView;
if (row instanceof ExpandableNotificationRow) {
@@ -656,6 +674,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
@@ -670,6 +689,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
protected void onDraw(Canvas canvas) {
if (mShouldDrawNotificationBackground
&& (mCurrentBounds.top < mCurrentBounds.bottom || mAmbientState.isDark())) {
@@ -686,6 +706,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
private void drawBackground(Canvas canvas) {
final int lockScreenLeft = mSidePaddings;
final int lockScreenRight = getWidth() - mSidePaddings;
@@ -729,6 +750,7 @@
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackgroundDimming() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground) {
@@ -755,6 +777,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void initView(Context context) {
mScroller = new OverScroller(getContext());
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
@@ -786,10 +809,12 @@
R.dimen.heads_up_status_bar_padding);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyHeightChangeListener(ExpandableView view) {
notifyHeightChangeListener(view, false /* needsAnimation */);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyHeightChangeListener(ExpandableView view, boolean needsAnimation) {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onHeightChanged(view, needsAnimation);
@@ -797,6 +822,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -816,6 +842,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// we layout all our children centered on the top
float centerX = getWidth() / 2.0f;
@@ -838,6 +865,7 @@
updateAlgorithmLayoutMinHeight();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
if (mAnimationsEnabled && (mIsExpanded || row != null && row.isPinned())) {
mNeedViewResizeAnimation = true;
@@ -845,18 +873,21 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
mAmbientState.setSpeedBumpIndex(newIndex);
mNoAmbient = noAmbient;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setChildLocationsChangedListener(
NotificationLogger.OnChildLocationsChangedListener listener) {
mListener = listener;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
public boolean isInVisibleLocation(ExpandableNotificationRow row) {
ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(row);
if (childViewState == null) {
@@ -871,12 +902,14 @@
return true;
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void setMaxLayoutHeight(int maxLayoutHeight) {
mMaxLayoutHeight = maxLayoutHeight;
mShelf.setMaxLayoutHeight(maxLayoutHeight);
updateAlgorithmHeightAndPadding();
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmHeightAndPadding() {
mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding,
mInterpolatedDarkAmount);
@@ -885,6 +918,7 @@
mAmbientState.setTopPadding(mTopPadding);
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmLayoutMinHeight() {
mAmbientState.setLayoutMinHeight(mQsExpanded || isHeadsUpTransition()
? getLayoutMinHeight() : 0);
@@ -894,6 +928,7 @@
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateChildren() {
updateScrollStateForAddedChildren();
mAmbientState.setCurrentScrollVelocity(mScroller.isFinished()
@@ -908,6 +943,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void onPreDrawDuringAnimation() {
mShelf.updateAppearance();
updateClippingToTopRoundedCorner();
@@ -916,6 +952,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateClippingToTopRoundedCorner() {
Float clipStart = (float) mTopPadding
+ mStackTranslation
@@ -938,6 +975,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollStateForAddedChildren() {
if (mChildrenToAddAnimated.isEmpty()) {
return;
@@ -961,6 +999,7 @@
clampScrollPosition();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForcedScroll() {
if (mForcedScroll != null && (!mForcedScroll.hasFocus()
|| !mForcedScroll.isAttachedToWindow())) {
@@ -982,6 +1021,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
@@ -990,10 +1030,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean isCurrentlyAnimating() {
return mStateAnimator.isRunning();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void clampScrollPosition() {
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY) {
@@ -1001,10 +1043,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getTopPadding() {
return mTopPadding;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setTopPadding(int topPadding, boolean animate) {
if (mRegularTopPadding != topPadding) {
mRegularTopPadding = topPadding;
@@ -1026,6 +1070,7 @@
*
* @param height the expanded height of the panel
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
mExpandedHeight = height;
setIsExpanded(height > 0);
@@ -1092,6 +1137,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setRequestedClipBounds(Rect clipRect) {
mRequestedClipBounds = clipRect;
updateClipping();
@@ -1100,10 +1146,12 @@
/**
* Return the height of the content ignoring the footer.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getIntrinsicContentHeight() {
return mIntrinsicContentHeight;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void updateClipping() {
boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1;
boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
@@ -1125,6 +1173,7 @@
* @return The translation at the beginning when expanding.
* Measured relative to the resting position.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getExpandTranslationStart() {
return -mTopPadding + getMinExpansionHeight();
}
@@ -1133,6 +1182,7 @@
* @return the position from where the appear transition starts when expanding.
* Measured in absolute height.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getAppearStartPosition() {
if (isHeadsUpTransition()) {
return mHeadsUpInset + mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
@@ -1145,6 +1195,7 @@
* intrinsic height, which also includes whether the notification is system expanded and
* is mainly used when dragging down from a heads up notification.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry == null) {
@@ -1165,6 +1216,7 @@
* @return the position from where the appear transition ends when expanding.
* Measured in absolute height.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getAppearEndPosition() {
int appearPosition;
int notGoneChildCount = getNotGoneChildCount();
@@ -1184,6 +1236,7 @@
return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isHeadsUpTransition() {
return mTrackingHeadsUp && mFirstVisibleBackgroundChild != null
&& mAmbientState.isAboveShelf(mFirstVisibleBackgroundChild);
@@ -1193,6 +1246,7 @@
* @param height the height of the panel
* @return the fraction of the appear animation that has been performed
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getAppearFraction(float height) {
float appearEndPosition = getAppearEndPosition();
float appearStartPosition = getAppearStartPosition();
@@ -1200,10 +1254,12 @@
/ (appearEndPosition - appearStartPosition);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getStackTranslation() {
return mStackTranslation;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setStackTranslation(float stackTranslation) {
if (stackTranslation != mStackTranslation) {
mStackTranslation = stackTranslation;
@@ -1218,19 +1274,23 @@
*
* @return either the layout height or the externally defined height, whichever is smaller
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private int getLayoutHeight() {
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public int getFirstItemMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
mLongPressListener = listener;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void setQsContainer(ViewGroup qsContainer) {
mQsContainer = qsContainer;
}
@@ -1240,6 +1300,7 @@
* re-invoking dismiss logic in case the notification has not made its way out yet).
*/
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildDismissed(View view) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (!row.isDismissed()) {
@@ -1257,6 +1318,8 @@
*
* @param view view (e.g. notification) to dismiss from the layout
*/
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void handleChildViewDismissed(View view) {
if (mDismissAllInProgress) {
return;
@@ -1296,6 +1359,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildSnappedBack(View animView, float targetLeft) {
mAmbientState.onDragFinished(animView);
updateContinuousShadowDrawing();
@@ -1316,12 +1380,14 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
// Returning true prevents alpha fading.
return !mFadeNotificationsOnDismiss;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onBeginDrag(View v) {
mFalsingManager.onNotificatonStartDismissing();
setSwipingInProgress(true);
@@ -1334,6 +1400,7 @@
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1342,6 +1409,7 @@
return false;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1351,17 +1419,20 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onDragCancelled(View v) {
mFalsingManager.onNotificatonStopDismissing();
setSwipingInProgress(false);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public float getFalsingThresholdFactor() {
return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public View getChildAtPosition(MotionEvent ev) {
View child = getChildAtPosition(ev.getX(), ev.getY());
if (child instanceof ExpandableNotificationRow) {
@@ -1382,6 +1453,7 @@
return child;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
float localTouchY = touchY - mTempInt2[1];
@@ -1412,12 +1484,14 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getChildAtPosition(float touchX, float touchY) {
return getChildAtPosition(touchX, touchY, true /* requireMinHeight */);
@@ -1431,6 +1505,7 @@
* @param requireMinHeight Whether a minimum height is required for a child to be returned.
* @return the child at the given location.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight) {
// find the view under the pointer, accounting for GONE views
@@ -1471,6 +1546,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public boolean canChildBeExpanded(View v) {
return v instanceof ExpandableNotificationRow
&& ((ExpandableNotificationRow) v).isExpandable()
@@ -1480,6 +1556,7 @@
/* Only ever called as a consequence of an expansion gesture in the shade. */
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUserExpandedChild(View v, boolean userExpanded) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1502,6 +1579,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpansionCancelled(View v) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setGroupExpansionChanging(false);
@@ -1509,6 +1587,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUserLockedChild(View v, boolean userLocked) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setUserLocked(userLocked);
@@ -1518,6 +1597,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void expansionStateChanged(boolean isExpanding) {
mExpandingNotification = isExpanding;
if (!mExpandedInThisMotion) {
@@ -1527,14 +1607,17 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getMaxExpandHeight(ExpandableView view) {
return view.getMaxContentHeight();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setScrollingEnabled(boolean enable) {
mScrollingEnabled = enable;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void lockScrollTo(View v) {
if (mForcedScroll == v) {
return;
@@ -1543,6 +1626,7 @@
scrollTo(v);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean scrollTo(View v) {
ExpandableView expandableView = (ExpandableView) v;
int positionInLinearLayout = getPositionInLinearLayout(v);
@@ -1564,6 +1648,7 @@
* @return the scroll necessary to make the bottom edge of {@param v} align with the top of
* the IME.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int targetScrollForView(ExpandableView v, int positionInLinearLayout) {
return positionInLinearLayout + v.getIntrinsicHeight() +
getImeInset() - getHeight()
@@ -1571,6 +1656,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mBottomInset = insets.getSystemWindowInsetBottom();
@@ -1588,6 +1674,7 @@
return insets;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private Runnable mReclamp = new Runnable() {
@Override
public void run() {
@@ -1599,28 +1686,34 @@
}
};
- private void setExpandingEnabled(boolean enable) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setExpandingEnabled(boolean enable) {
mExpandHelper.setEnabled(enable);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isScrollingEnabled() {
return mScrollingEnabled;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isAntiFalsingNeeded() {
return onKeyguard();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void setSwipingInProgress(boolean isSwiped) {
mSwipingInProgress = isSwiped;
if (isSwiped) {
@@ -1629,6 +1722,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
@@ -1639,12 +1733,14 @@
initView(getContext());
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
true /* isDismissAll */);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void snapViewIfNeeded(ExpandableNotificationRow child) {
boolean animate = mIsExpanded || isPinnedHeadsUp(child);
// If the child is showing the notification menu snap to that
@@ -1653,11 +1749,13 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
return this;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked() == MotionEvent.ACTION_UP;
@@ -1706,6 +1804,7 @@
return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void dispatchDownEventToScroller(MotionEvent ev) {
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
@@ -1714,6 +1813,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onGenericMotionEvent(MotionEvent event) {
if (!isScrollingEnabled() || !mIsExpanded || mSwipingInProgress || mExpandingNotification
|| mDisallowScrollingInThisMotion) {
@@ -1746,6 +1846,7 @@
return super.onGenericMotionEvent(event);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean onScrollTouch(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
@@ -1882,10 +1983,12 @@
return true;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
protected boolean isInsideQsContainer(MotionEvent ev) {
return ev.getY() < mQsContainer.getBottom();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void onOverScrollFling(boolean open, int initialVelocity) {
if (mOverscrollTopChangedListener != null) {
mOverscrollTopChangedListener.flingTopOverscroll(initialVelocity, open);
@@ -1901,6 +2004,7 @@
* @return The amount of scrolling to be performed by the scroller,
* not handled by the overScroll amount.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private float overScrollUp(int deltaY, int range) {
deltaY = Math.max(deltaY, 0);
float currentTopAmount = getCurrentOverScrollAmount(true);
@@ -1934,6 +2038,7 @@
* @return The amount of scrolling to be performed by the scroller,
* not handled by the overScroll amount.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private float overScrollDown(int deltaY) {
deltaY = Math.min(deltaY, 0);
float currentBottomAmount = getCurrentOverScrollAmount(false);
@@ -1958,6 +2063,7 @@
return scrollAmount;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -1975,12 +2081,14 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -1988,6 +2096,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -1996,10 +2105,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setFinishScrollingCallback(Runnable runnable) {
mFinishScrollingCallback = runnable;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void animateScroll() {
if (mScroller.computeScrollOffset()) {
int oldY = mOwnScrollY;
@@ -2030,6 +2141,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean customOverScrollBy(int deltaY, int scrollY, int scrollRangeY,
int maxOverScrollY) {
@@ -2061,6 +2173,7 @@
* @param onTop Should the effect be applied on top of the scroller.
* @param animate Should an animation be performed.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
}
@@ -2073,6 +2186,8 @@
* @param onTop Should the effect be applied on top of the scroller.
* @param animate Should an animation be performed.
*/
+
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
setOverScrollAmount(amount, onTop, animate, true);
}
@@ -2085,6 +2200,7 @@
* @param animate Should an animation be performed.
* @param cancelAnimators Should running animations be cancelled.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
boolean cancelAnimators) {
setOverScrollAmount(amount, onTop, animate, cancelAnimators, isRubberbanded(onTop));
@@ -2100,6 +2216,7 @@
* @param isRubberbanded The value which will be passed to
* {@link OnOverscrollTopChangedListener#onOverscrollTopChanged}
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
boolean cancelAnimators, boolean isRubberbanded) {
if (cancelAnimators) {
@@ -2108,6 +2225,7 @@
setOverScrollAmountInternal(amount, onTop, animate, isRubberbanded);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void setOverScrollAmountInternal(float amount, boolean onTop, boolean animate,
boolean isRubberbanded) {
amount = Math.max(0, amount);
@@ -2123,6 +2241,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyOverscrollTopListener(float amount, boolean isRubberbanded) {
mExpandHelper.onlyObserveMovements(amount > 1.0f);
if (mDontReportNextOverScroll) {
@@ -2134,19 +2253,23 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setOverscrollTopChangedListener(
OnOverscrollTopChangedListener overscrollTopChangedListener) {
mOverscrollTopChangedListener = overscrollTopChangedListener;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getCurrentOverScrollAmount(boolean top) {
return mAmbientState.getOverScrollAmount(top);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getCurrentOverScrolledPixels(boolean top) {
return top ? mOverScrolledTopPixels : mOverScrolledBottomPixels;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setOverScrolledPixels(float amount, boolean onTop) {
if (onTop) {
mOverScrolledTopPixels = amount;
@@ -2155,6 +2278,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onCustomOverScrolled(int scrollY, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
@@ -2174,6 +2298,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void springBack() {
int scrollRange = getScrollRange();
boolean overScrolledTop = mOwnScrollY <= 0;
@@ -2197,6 +2322,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getScrollRange() {
// In current design, it only use the top HUN to treat all of HUNs
// although there are more than one HUNs
@@ -2210,6 +2336,7 @@
return scrollRange;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getImeInset() {
return Math.max(0, mBottomInset - (getRootView().getHeight() - getHeight()));
}
@@ -2217,6 +2344,7 @@
/**
* @return the first child which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ExpandableView getFirstChildNotGone() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2231,6 +2359,7 @@
/**
* @return the child before the given view which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ExpandableView getViewBeforeView(ExpandableView view) {
ExpandableView previousView = null;
int childCount = getChildCount();
@@ -2250,6 +2379,7 @@
* @return The first child which has visibility unequal to GONE which is currently below the
* given translationY or equal to it.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private View getFirstChildBelowTranlsationY(float translationY, boolean ignoreChildren) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2281,6 +2411,7 @@
/**
* @return the last child which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public View getLastChildNotGone() {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -2295,6 +2426,7 @@
/**
* @return the number of children which have visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getNotGoneChildCount() {
int childCount = getChildCount();
int count = 0;
@@ -2307,6 +2439,7 @@
return count;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
int height = 0;
float previousPaddingRequest = mPaddingBetweenElements;
@@ -2380,15 +2513,18 @@
mAmbientState.setLayoutMaxHeight(mContentHeight);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isPulsing(NotificationData.Entry entry) {
return mAmbientState.isPulsing(entry);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasPulsingNotifications() {
return mPulsing;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateScrollability() {
boolean scrollable = !mQsExpanded && getScrollRange() > 0;
if (scrollable != mScrollable) {
@@ -2398,6 +2534,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForwardAndBackwardScrollability() {
boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
@@ -2410,6 +2547,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackground() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground || mAmbientState.isFullyDark()) {
@@ -2437,6 +2575,7 @@
mAnimateNextBackgroundTop = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void abortBackgroundAnimators() {
if (mBottomAnimator != null) {
mBottomAnimator.cancel();
@@ -2446,10 +2585,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean areBoundsAnimating() {
return mBottomAnimator != null || mTopAnimator != null;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startBackgroundAnimation() {
// left and right are always instantly applied
mCurrentBounds.left = mBackgroundBounds.left;
@@ -2458,6 +2599,7 @@
startTopAnimation();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startTopAnimation() {
int previousEndValue = mEndAnimationRect.top;
int newEndValue = mBackgroundBounds.top;
@@ -2506,6 +2648,7 @@
mTopAnimator = animator;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startBottomAnimation() {
int previousStartValue = mStartAnimationRect.bottom;
int previousEndValue = mEndAnimationRect.bottom;
@@ -2554,11 +2697,13 @@
mBottomAnimator = animator;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setBackgroundTop(int top) {
mCurrentBounds.top = top;
invalidate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setBackgroundBottom(int bottom) {
mCurrentBounds.bottom = bottom;
invalidate();
@@ -2567,6 +2712,7 @@
/**
* Update the background bounds to the new desired bounds
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackgroundBounds() {
getLocationInWindow(mTempInt2);
mBackgroundBounds.left = mTempInt2[0] + mSidePaddings;
@@ -2628,6 +2774,7 @@
mBackgroundBounds.bottom = Math.max(bottom, top);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getFirstPinnedHeadsUp() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2643,6 +2790,7 @@
return null;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getLastChildWithBackground() {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -2655,6 +2803,7 @@
return null;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getFirstChildWithBackground() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2674,6 +2823,7 @@
* numbers mean that the finger/cursor is moving down the screen,
* which means we want to scroll towards the top.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
protected void fling(int velocityY) {
if (getChildCount() > 0) {
int scrollRange = getScrollRange();
@@ -2711,6 +2861,7 @@
* @return Whether a fling performed on the top overscroll edge lead to the expanded
* overScroll view (i.e QS).
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean shouldOverScrollFling(int initialVelocity) {
float topOverScroll = getCurrentOverScrollAmount(true);
return mScrolledToTopOnFirstDown
@@ -2728,6 +2879,7 @@
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
int topPadding = (int) qsHeight;
@@ -2742,10 +2894,12 @@
setExpandedHeight(mExpandedHeight);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setMaxTopPadding(int maxTopPadding) {
mMaxTopPadding = maxTopPadding;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getLayoutMinHeight() {
if (isHeadsUpTransition()) {
return getTopHeadsUpPinnedHeight();
@@ -2753,6 +2907,7 @@
return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getFirstChildIntrinsicHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
int firstChildMinHeight = firstChild != null
@@ -2766,10 +2921,13 @@
return firstChildMinHeight;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getTopPaddingOverflow() {
return mTopPaddingOverflow;
}
+
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getPeekHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
@@ -2781,10 +2939,12 @@
return mIntrinsicPadding + firstChildMinHeight + shelfHeight;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int clampPadding(int desiredPadding) {
return Math.max(desiredPadding, mIntrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private float getRubberBandFactor(boolean onTop) {
if (!onTop) {
return RUBBER_BAND_FACTOR_NORMAL;
@@ -2804,11 +2964,13 @@
* rubberbanded, false if it is technically an overscroll but rather a motion to expand the
* overscroll view (e.g. expand QS).
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isRubberbanded(boolean onTop) {
return !onTop || mExpandedInThisMotion || mIsExpansionChanging || mPanelTracking
|| !mScrolledToTopOnFirstDown;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void endDrag() {
setIsBeingDragged(false);
@@ -2822,12 +2984,14 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void transformTouchEvent(MotionEvent ev, View sourceView, View targetView) {
ev.offsetLocation(sourceView.getX(), sourceView.getY());
ev.offsetLocation(-targetView.getX(), -targetView.getY());
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onInterceptTouchEvent(MotionEvent ev) {
initDownStates(ev);
handleEmptySpaceClick(ev);
@@ -2863,6 +3027,7 @@
return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void handleEmptySpaceClick(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
@@ -2880,6 +3045,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void initDownStates(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mExpandedInThisMotion = false;
@@ -2892,10 +3058,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setChildTransferInProgress(boolean childTransferInProgress) {
mChildTransferInProgress = childTransferInProgress;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
@@ -2906,6 +3074,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
public void cleanUpViewState(View child) {
if (child == mTranslatingParentView) {
@@ -2915,6 +3084,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
super.requestDisallowInterceptTouchEvent(disallowIntercept);
if (disallowIntercept) {
@@ -2922,6 +3092,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewRemovedInternal(View child, ViewGroup container) {
if (mChangePositionInProgress) {
// This is only a position change, don't do anything special
@@ -2946,6 +3117,7 @@
focusNextViewIfFocused(child);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void focusNextViewIfFocused(View view) {
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -2965,6 +3137,7 @@
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isChildInGroup(View child) {
return child instanceof ExpandableNotificationRow
&& mGroupManager.isChildInGroupWithSummary(
@@ -2977,6 +3150,7 @@
* @param child The view to generate the remove animation for.
* @return Whether an animation was generated.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean generateRemoveAnimation(View child) {
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
@@ -3002,6 +3176,7 @@
return false;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isClickedHeadsUp(View child) {
return HeadsUpUtil.isClickedHeadsUpNotification(child);
}
@@ -3011,6 +3186,7 @@
*
* @return whether any child was removed from the list to animate
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) {
boolean hasAddEvent = false;
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
@@ -3035,6 +3211,7 @@
* @return whether a view is not a top level child but a child notification and that group is
* not expanded
*/
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isChildInInvisibleGroup(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3052,6 +3229,7 @@
*
* @param removedChild the removed child
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
@@ -3080,6 +3258,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getIntrinsicHeight(View view) {
if (view instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) view;
@@ -3088,6 +3267,7 @@
return view.getHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getPositionInLinearLayout(View requestedView) {
ExpandableNotificationRow childInGroup = null;
ExpandableNotificationRow requestedRow = null;
@@ -3149,11 +3329,13 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onViewAdded(View child) {
super.onViewAdded(child);
onViewAddedInternal(child);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateFirstAndLastBackgroundViews() {
ActivatableNotificationView firstChild = getFirstChildWithBackground();
ActivatableNotificationView lastChild = getLastChildWithBackground();
@@ -3172,6 +3354,7 @@
invalidate();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
((ExpandableView) child).setOnHeightChangedListener(this);
@@ -3180,6 +3363,7 @@
updateChronometerForChild(child);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateHideSensitiveForChild(View child) {
if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
@@ -3188,15 +3372,18 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) {
onViewRemovedInternal(row, childrenContainer);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildAdded(View row) {
onViewAddedInternal(row);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
updateNotificationAnimationStates();
@@ -3207,6 +3394,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateNotificationAnimationStates() {
boolean running = mAnimationsEnabled || hasPulsingNotifications();
mShelf.setAnimationsEnabled(running);
@@ -3218,18 +3406,21 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateAnimationState(View child) {
updateAnimationState((mAnimationsEnabled || hasPulsingNotifications())
&& (mIsExpanded || isPinnedHeadsUp(child)), child);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpandingNotification(ExpandableNotificationRow row) {
mAmbientState.setExpandingNotification(row);
requestChildrenUpdate();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void bindRow(ExpandableNotificationRow row) {
row.setHeadsUpAnimatingAwayListener(animatingAway -> {
mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway);
@@ -3238,11 +3429,13 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateAnimationState(boolean running, View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3250,12 +3443,14 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public boolean isAddOrRemoveAnimationPending() {
return mNeedsAnimation
&& (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void generateAddAnimation(View child, boolean fromMoreCard) {
if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress) {
// Generate Animations
@@ -3272,6 +3467,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void changeViewPosition(View child, int newIndex) {
int currentIndex = indexOfChild(child);
@@ -3303,6 +3499,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startAnimationToState() {
if (mNeedsAnimation) {
generateAllAnimationEvents();
@@ -3322,6 +3519,7 @@
mGoToFullShadeDelay = 0;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateAllAnimationEvents() {
generateHeadsUpAnimationEvents();
generateChildRemovalEvents();
@@ -3341,6 +3539,7 @@
generatePulsingAnimationEvent();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateHeadsUpAnimationEvents() {
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
ExpandableNotificationRow row = eventPair.first;
@@ -3383,6 +3582,7 @@
mAddedHeadsUpChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
return false;
@@ -3390,6 +3590,7 @@
return true;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateGroupExpansionEvent() {
// Generate a group expansion/collapsing event if there is such a group at all
if (mExpandedGroupView != null) {
@@ -3399,6 +3600,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateViewResizeEvent() {
if (mNeedViewResizeAnimation) {
boolean hasDisappearAnimation = false;
@@ -3419,6 +3621,7 @@
mNeedViewResizeAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateSnapBackEvents() {
for (View child : mSnappedBackChildren) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3427,6 +3630,7 @@
mSnappedBackChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDragEvents() {
for (View child : mDragAnimPendingChildren) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3435,6 +3639,7 @@
mDragAnimPendingChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateChildRemovalEvents() {
for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
@@ -3476,6 +3681,7 @@
mChildrenToRemoveAnimated.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generatePositionChangeEvents() {
for (View child : mChildrenChangingPositions) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3489,6 +3695,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateChildAdditionEvents() {
for (View child : mChildrenToAddAnimated) {
if (mFromMoreCardAdditions.contains(child)) {
@@ -3504,6 +3711,7 @@
mFromMoreCardAdditions.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateTopPaddingEvent() {
if (mTopPaddingNeedsAnimation) {
AnimationEvent event;
@@ -3520,6 +3728,7 @@
mTopPaddingNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateActivateEvent() {
if (mActivateNeedsAnimation) {
mAnimationEvents.add(
@@ -3528,6 +3737,7 @@
mActivateNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateAnimateEverythingEvent() {
if (mEverythingNeedsAnimation) {
mAnimationEvents.add(
@@ -3536,6 +3746,7 @@
mEverythingNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDimmedEvent() {
if (mDimmedNeedsAnimation) {
mAnimationEvents.add(
@@ -3544,6 +3755,7 @@
mDimmedNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateHideSensitiveEvent() {
if (mHideSensitiveNeedsAnimation) {
mAnimationEvents.add(
@@ -3552,6 +3764,7 @@
mHideSensitiveNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDarkEvent() {
if (mDarkNeedsAnimation) {
AnimationEvent ev = new AnimationEvent(null,
@@ -3565,6 +3778,7 @@
mDarkNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateGoToFullShadeEvent() {
if (mGoToFullShadeNeedsAnimation) {
mAnimationEvents.add(
@@ -3573,6 +3787,7 @@
mGoToFullShadeNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
@@ -3682,6 +3897,7 @@
return mIsBeingDragged;
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
return new StackScrollAlgorithm(context);
}
@@ -3689,6 +3905,7 @@
/**
* @return Whether the specified motion event is actually happening over the content.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isInContentBounds(MotionEvent event) {
return isInContentBounds(event.getY());
}
@@ -3696,10 +3913,12 @@
/**
* @return Whether a y coordinate is inside the content.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isInContentBounds(float y) {
return y < getHeight() - getEmptyBottomMargin();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
@@ -3709,6 +3928,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (!hasWindowFocus) {
@@ -3717,6 +3937,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void clearChildFocus(View child) {
super.clearChildFocus(child);
if (mForcedScroll == child) {
@@ -3724,37 +3945,45 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowLongPress() {
cancelLongPress();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowDismiss() {
mDisallowDismissInThisMotion = true;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void cancelLongPress() {
mSwipeHelper.cancelLongPress();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isScrolledToTop() {
return mOwnScrollY == 0;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isScrolledToBottom() {
return mOwnScrollY >= getScrollRange();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public View getHostView() {
return this;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getEmptyBottomMargin() {
return Math.max(mMaxLayoutHeight - mContentHeight, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void checkSnoozeLeavebehind() {
if (mCheckForLeavebehind) {
mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
@@ -3764,16 +3993,19 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void resetCheckSnoozeLeavebehind() {
mCheckForLeavebehind = true;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onExpansionStarted() {
mIsExpansionChanging = true;
mAmbientState.setExpansionChanging(true);
checkSnoozeLeavebehind();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onExpansionStopped() {
mIsExpansionChanging = false;
resetCheckSnoozeLeavebehind();
@@ -3786,6 +4018,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearUserLockedViews() {
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
@@ -3796,6 +4029,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTemporaryViews() {
// lets make sure nothing is transient anymore
clearTemporaryViewsInGroup(this);
@@ -3808,27 +4042,32 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
viewGroup.removeTransientView(viewGroup.getTransientView(0));
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onPanelTrackingStarted() {
mPanelTracking = true;
mAmbientState.setPanelTracking(true);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onPanelTrackingStopped() {
mPanelTracking = false;
mAmbientState.setPanelTracking(false);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void resetScrollPosition() {
mScroller.abortAnimation();
setOwnScrollY(0);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
@@ -3844,6 +4083,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateChronometers() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -3851,6 +4091,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateChronometerForChild(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3859,6 +4100,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
updateContentHeight();
updateScrollPositionOnExpandInBottom(view);
@@ -3878,11 +4120,13 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onReset(ExpandableView view) {
updateAnimationState(view);
updateChronometerForChild(view);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
if (view instanceof ExpandableNotificationRow && !onKeyguard()) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -3907,15 +4151,18 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setOnHeightChangedListener(
ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
this.mOnHeightChangedListener = mOnHeightChangedListener;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
mOnEmptySpaceClickListener = listener;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onChildAnimationFinished() {
setAnimationRunning(false);
requestChildrenUpdate();
@@ -3924,6 +4171,7 @@
clearHeadsUpDisappearRunning();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearHeadsUpDisappearRunning() {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
@@ -3939,6 +4187,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTransient() {
for (ExpandableView view : mClearTransientViewsWhenFinished) {
StackStateAnimator.removeTransientView(view);
@@ -3946,6 +4195,7 @@
mClearTransientViewsWhenFinished.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void runAnimationFinishedRunnables() {
for (Runnable runnable : mAnimationFinishedRunnables) {
runnable.run();
@@ -3956,6 +4206,7 @@
/**
* See {@link AmbientState#setDimmed}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDimmed(boolean dimmed, boolean animate) {
dimmed &= onKeyguard();
mAmbientState.setDimmed(dimmed);
@@ -3970,15 +4221,18 @@
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
boolean isDimmed() {
return mAmbientState.isDimmed();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setDimAmount(float dimAmount) {
mDimAmount = dimAmount;
updateBackgroundDimming();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void animateDimmed(boolean dimmed) {
if (mDimAnimator != null) {
mDimAnimator.cancel();
@@ -3994,8 +4248,8 @@
mDimAnimator.addUpdateListener(mDimUpdateListener);
mDimAnimator.start();
}
-
- private void setHideSensitive(boolean hideSensitive, boolean animate) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setHideSensitive(boolean hideSensitive, boolean animate) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -4015,6 +4269,7 @@
/**
* See {@link AmbientState#setActivatedChild}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setActivatedChild(ActivatableNotificationView activatedChild) {
mAmbientState.setActivatedChild(activatedChild);
if (mAnimationsEnabled) {
@@ -4024,10 +4279,12 @@
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ActivatableNotificationView getActivatedChild() {
return mAmbientState.getActivatedChild();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void applyCurrentState() {
mCurrentStackScrollState.apply();
if (mListener != null) {
@@ -4040,6 +4297,7 @@
updateClippingToTopRoundedCorner();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateViewShadows() {
// we need to work around an issue where the shadow would not cast between siblings when
// their z difference is between 0 and 0.1
@@ -4082,6 +4340,7 @@
*
* @param lightTheme True if light theme should be used.
*/
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
public void updateDecorViews(boolean lightTheme) {
if (lightTheme == mUsingLightTheme) {
return;
@@ -4094,6 +4353,7 @@
mEmptyShadeView.setTextColor(textColor);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void goToFullShade(long delay) {
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
@@ -4101,15 +4361,18 @@
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void cancelExpandHelper() {
mExpandHelper.cancel();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setIntrinsicPadding(int intrinsicPadding) {
mIntrinsicPadding = intrinsicPadding;
mAmbientState.setIntrinsicPadding(intrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getIntrinsicPadding() {
return mIntrinsicPadding;
}
@@ -4117,11 +4380,13 @@
/**
* @return the y position of the first notification
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getNotificationsTopY() {
return mTopPadding + getStackTranslation();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean shouldDelayChildPressedState() {
return true;
}
@@ -4129,6 +4394,7 @@
/**
* See {@link AmbientState#setDark}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDark(boolean dark, boolean animate, @Nullable PointF touchWakeUpScreenLocation) {
if (mAmbientState.isDark() == dark) {
return;
@@ -4147,10 +4413,12 @@
notifyHeightChangeListener(mShelf);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updatePanelTranslation() {
setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setVerticalPanelTranslation(float verticalPanelTranslation) {
mVerticalPanelTranslation = verticalPanelTranslation;
updatePanelTranslation();
@@ -4161,11 +4429,13 @@
* not {@link #onDraw(Canvas)} is called). This method should be called whenever the
* {@link #mAmbientState}'s dark mode is toggled.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateWillNotDraw() {
boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
setWillNotDraw(!willDraw);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setDarkAmount(float darkAmount) {
setDarkAmount(darkAmount, darkAmount);
}
@@ -4179,6 +4449,7 @@
* @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the
* animation curve.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) {
mLinearDarkAmount = linearDarkAmount;
mInterpolatedDarkAmount = interpolatedDarkAmount;
@@ -4201,6 +4472,7 @@
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void notifyDarkAnimationStart(boolean dark) {
// We only swap the scaling factor if we're fully dark or fully awake to avoid
// interpolation issues when playing with the power button.
@@ -4212,6 +4484,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public long getDarkAnimationDuration(boolean dark) {
long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
// Longer animation when sleeping with more than 1 notification
@@ -4221,6 +4494,7 @@
return duration;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
if (screenLocation == null || screenLocation.y < mTopPadding) {
return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
@@ -4236,6 +4510,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private int getNotGoneIndex(View child) {
int count = getChildCount();
int notGoneIndex = 0;
@@ -4251,6 +4526,7 @@
return -1;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setFooterView(@NonNull FooterView footerView) {
int index = -1;
if (mFooterView != null) {
@@ -4261,6 +4537,7 @@
addView(mFooterView, index);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
int index = -1;
if (mEmptyShadeView != null) {
@@ -4271,6 +4548,7 @@
addView(mEmptyShadeView, index);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateEmptyShadeView(boolean visible) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
@@ -4282,6 +4560,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooterView(boolean visible, boolean showDismissView) {
if (mFooterView == null) {
return;
@@ -4291,12 +4570,14 @@
mFooterView.setSecondaryVisible(showDismissView, animate);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDismissAllInProgress(boolean dismissAllInProgress) {
mDismissAllInProgress = dismissAllInProgress;
mAmbientState.setDismissAllInProgress(dismissAllInProgress);
handleDismissAllClipping();
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private void handleDismissAllClipping() {
final int count = getChildCount();
boolean previousChildWillBeDismissed = false;
@@ -4314,24 +4595,29 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFooterViewNotGone() {
return mFooterView != null
&& mFooterView.getVisibility() != View.GONE
&& !mFooterView.willBeGone();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFooterViewContentVisible() {
return mFooterView != null && mFooterView.isContentVisible();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getFooterViewHeight() {
return mFooterView == null ? 0 : mFooterView.getHeight() + mPaddingBetweenElements;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getEmptyShadeViewHeight() {
return mEmptyShadeView.getHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getBottomMostNotificationBottom() {
final int count = getChildCount();
float max = 0;
@@ -4349,15 +4635,18 @@
return max + getStackTranslation();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setStatusBar(StatusBar statusBar) {
this.mStatusBar = statusBar;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setGroupManager(NotificationGroupManager groupManager) {
this.mGroupManager = groupManager;
mGroupManager.setOnGroupChangeListener(this);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
mEverythingNeedsAnimation = true;
@@ -4366,6 +4655,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isBelowLastNotification(float touchX, float touchY) {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -4397,6 +4687,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled
&& (mIsExpanded || changedRow.isPinned());
@@ -4417,12 +4708,14 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
mStatusBar.requestNotificationUpdate();
}
/** @hide */
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
event.setScrollable(mScrollable);
@@ -4433,6 +4726,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
if (mScrollable) {
@@ -4453,6 +4747,7 @@
/** @hide */
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
@@ -4485,10 +4780,12 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupsChanged() {
mStatusBar.requestNotificationUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void generateChildOrderChangedEvent() {
if (mIsExpanded && mAnimationsEnabled) {
mGenerateChildOrderChangedEvent = true;
@@ -4498,29 +4795,35 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getContainerChildCount() {
return getChildCount();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public View getContainerChildAt(int i) {
return getChildAt(i);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void removeContainerView(View v) {
removeView(v);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
addView(v);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void runAfterAnimationFinished(Runnable runnable) {
mAnimationFinishedRunnables.add(runnable);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
mAmbientState.setHeadsUpManager(headsUpManager);
@@ -4528,6 +4831,7 @@
mHeadsUpManager.setAnimationStateHandler(this);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
@@ -4539,6 +4843,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShadeExpanded(boolean shadeExpanded) {
mAmbientState.setShadeExpanded(shadeExpanded);
mStateAnimator.setShadeExpanded(shadeExpanded);
@@ -4551,31 +4856,37 @@
* @param height the height of the screen
* @param bottomBarHeight the height of the bar on the bottom
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpBoundaries(int height, int bottomBarHeight) {
mAmbientState.setMaxHeadsUpTranslation(height - bottomBarHeight);
mStateAnimator.setHeadsUpAppearHeightBottom(height);
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setTrackingHeadsUp(ExpandableNotificationRow row) {
mTrackingHeadsUp = row != null;
mRoundnessManager.setTrackingHeadsUp(row);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setScrimController(ScrimController scrimController) {
mScrimController = scrimController;
mScrimController.setScrimBehindChangeRunnable(this::updateBackgroundDimming);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void forceNoOverlappingRendering(boolean force) {
mForceNoOverlappingRendering = force;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasOverlappingRendering() {
return !mForceNoOverlappingRendering && super.hasOverlappingRendering();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationRunning(boolean animationRunning) {
if (animationRunning != mAnimationRunning) {
if (animationRunning) {
@@ -4588,10 +4899,12 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isExpanded() {
return mIsExpanded;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setPulsing(boolean pulsing, boolean animated) {
if (!mPulsing && !pulsing) {
return;
@@ -4607,6 +4920,7 @@
mNeedsAnimation |= animated;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void generatePulsingAnimationEvent() {
if (mNeedingPulseAnimation != null) {
int type = mPulsing ? AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR
@@ -4616,16 +4930,19 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpanded(boolean qsExpanded) {
mQsExpanded = qsExpanded;
updateAlgorithmLayoutMinHeight();
updateScrollability();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpansionFraction(float qsExpansionFraction) {
mQsExpansionFraction = qsExpansionFraction;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setOwnScrollY(int ownScrollY) {
if (ownScrollY != mOwnScrollY) {
// We still want to call the normal scrolled changed for accessibility reasons
@@ -4636,6 +4953,7 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShelf(NotificationShelf shelf) {
int index = -1;
if (mShelf != null) {
@@ -4649,10 +4967,12 @@
shelf.bind(mAmbientState, this);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationShelf getNotificationShelf() {
return mShelf;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
mMaxDisplayedNotifications = maxDisplayedNotifications;
@@ -4661,25 +4981,30 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
updateAlgorithmLayoutMinHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getMinExpansionHeight() {
return mShelf.getIntrinsicHeight() - (mShelf.getIntrinsicHeight() - mStatusBarHeight) / 2;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setInHeadsUpPinnedMode(boolean inHeadsUpPinnedMode) {
mInHeadsUpPinnedMode = inHeadsUpPinnedMode;
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
@@ -4703,10 +5028,12 @@
onUpdateRowStates();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpandingVelocity(float expandingVelocity) {
mAmbientState.setExpandingVelocity(expandingVelocity);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getOpeningHeight() {
if (mEmptyShadeView.getVisibility() == GONE) {
return getMinExpansionHeight();
@@ -4715,29 +5042,34 @@
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setIsFullWidth(boolean isFullWidth) {
mAmbientState.setPanelFullWidth(isFullWidth);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUnlockHintRunning(boolean running) {
mAmbientState.setUnlockHintRunning(running);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsCustomizerShowing(boolean isShowing) {
mAmbientState.setQsCustomizerShowing(isShowing);
requestChildrenUpdate();
}
- @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) {
mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setAntiBurnInOffsetX(int antiBurnInOffsetX) {
mAntiBurnInOffsetX = antiBurnInOffsetX;
updatePanelTranslation();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
+ " alpha:%f scrollY:%d maxTopPadding:%d showShelfOnly=%s"
@@ -4755,6 +5087,7 @@
mQsExpansionFraction));
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFullyDark() {
return mAmbientState.isFullyDark();
}
@@ -4765,6 +5098,7 @@
*
* @param listener the listener to notify.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
mExpandedHeightListeners.add(listener);
}
@@ -4772,24 +5106,29 @@
/**
* Stop a listener from listening to the expandedHeight.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void removeOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
mExpandedHeightListeners.remove(listener);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpAppearanceController(
HeadsUpAppearanceController headsUpAppearanceController) {
mHeadsUpAppearanceController = headsUpAppearanceController;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setIconAreaController(NotificationIconAreaController controller) {
mIconAreaController = controller;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void manageNotifications(View v) {
Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void clearAllNotifications() {
// animate-swipe all dismissable notifications, then animate the shade closed
int numChildren = getChildCount();
@@ -4852,6 +5191,7 @@
performDismissAllAnimations(viewsToHide);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
Runnable animationFinishAction = () -> {
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
@@ -4884,6 +5224,7 @@
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void inflateFooterView() {
FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_footer, this, false);
@@ -4895,7 +5236,8 @@
setFooterView(footerView);
}
- private void inflateEmptyShadeView() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private void inflateEmptyShadeView() {
EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
@@ -4905,6 +5247,7 @@
/**
* Updates expanded, dimmed and locked states of notification rows.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onUpdateRowStates() {
changeViewPosition(mFooterView, -1);
@@ -4925,13 +5268,15 @@
mScrimController.setNotificationCount(getNotGoneChildCount());
}
- public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setNotificationPanel(NotificationPanelView notificationPanelView) {
mNotificationPanel = notificationPanelView;
}
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnEmptySpaceClickListener {
void onEmptySpaceClicked(float x, float y);
}
@@ -4939,6 +5284,7 @@
/**
* A listener that gets notified when the overscroll at the top has changed.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnOverscrollTopChangedListener {
/**
@@ -4962,7 +5308,8 @@
void flingTopOverscroll(float velocity, boolean open);
}
- private class NotificationSwipeHelper extends SwipeHelper
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private class NotificationSwipeHelper extends SwipeHelper
implements NotificationSwipeActionHelper {
private static final long COVER_MENU_DELAY = 4000;
private Runnable mFalsingCheck;
@@ -5158,7 +5505,8 @@
}
}
- public boolean hasActiveNotifications() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public boolean hasActiveNotifications() {
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
@@ -5167,6 +5515,7 @@
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onDraggedDown(View startingChild, int dragLengthY) {
if (mStatusBarState == StatusBarState.KEYGUARD
&& hasActiveNotifications() && (!mStatusBar.isDozing() || mStatusBar.isPulsing())) {
@@ -5189,6 +5538,7 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onDragDownReset() {
setDimmed(true /* dimmed */, true /* animated */);
resetScrollPosition();
@@ -5196,27 +5546,32 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onCrossedThreshold(boolean above) {
setDimmed(!above /* dimmed */, true /* animate */);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onTouchSlopExceeded() {
cancelLongPress();
checkSnoozeLeavebehind();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setEmptyDragAmount(float amount) {
mNotificationPanel.setEmptyDragAmount(amount);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isFalsingCheckNeeded() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
- public void updateSpeedBumpIndex() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5236,6 +5591,7 @@
updateSpeedBumpIndex(speedBumpIndex, noAmbient);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isTouchInView(MotionEvent ev, View view) {
if (view == null) {
return false;
@@ -5253,6 +5609,7 @@
return ret;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| !mAmbientState.getDraggedViews().isEmpty();
@@ -5267,15 +5624,19 @@
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void closeControlsIfOutsideTouch(MotionEvent ev) {
mSwipeHelper.closeControlsIfOutsideTouch(ev);
}
- static class AnimationEvent {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[]{
@@ -5575,7 +5936,8 @@
}
}
- private final StateListener mStateListener = new StateListener() {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ private final StateListener mStateListener = new StateListener() {
@Override
public void onStatePreChange(int oldState, int newState) {
if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 426a0c15..fd32b5a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5296,7 +5296,9 @@
try {
INotificationManager notificationManager = mInjector.getNotificationManager();
try {
- notificationManager.enqueueNotificationWithTag(packageName, packageName,
+ // The calling uid must match either the package or op package, so use an op
+ // package that matches the cleared calling identity.
+ notificationManager.enqueueNotificationWithTag(packageName, "android",
id.mTag, id.mId, notification, userId);
} catch (RemoteException e) {
/* ignore - local call */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ce71dd2..03b7652 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -35,6 +35,8 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -203,6 +205,7 @@
import com.android.server.lights.LightsManager;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.pm.PackageManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -470,8 +473,8 @@
// Gather all notification listener components for candidate pkgs.
Set<ComponentName> approvedListeners =
mListeners.queryPackageForServices(whitelisted,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ComponentName cn : approvedListeners) {
try {
getBinderService().setNotificationListenerAccessGrantedForUser(cn,
@@ -507,8 +510,8 @@
// only be one
Set<ComponentName> approvedAssistants =
mAssistants.queryPackageForServices(defaultAssistantAccess,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ComponentName cn : approvedAssistants) {
try {
getBinderService().setNotificationAssistantAccessGrantedForUser(
@@ -1377,7 +1380,7 @@
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
- IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal) {
+ IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1390,7 +1393,7 @@
mUgmInternal = ugmInternal;
mPackageManager = packageManager;
mPackageManagerClient = packageManagerClient;
- mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps = appOps;
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -1544,7 +1547,8 @@
LocalServices.getService(UsageStatsManagerInternal.class),
LocalServices.getService(DevicePolicyManagerInternal.class),
UriGrantsManager.getService(),
- LocalServices.getService(UriGrantsManagerInternal.class));
+ LocalServices.getService(UriGrantsManagerInternal.class),
+ (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -2234,6 +2238,60 @@
}
@Override
+ public void setNotificationDelegate(String callingPkg, String delegate) {
+ checkCallerIsSameApp(callingPkg);
+ final int callingUid = Binder.getCallingUid();
+ UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ try {
+ ApplicationInfo info =
+ mPackageManager.getApplicationInfo(delegate,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ user.getIdentifier());
+ if (info != null) {
+ mPreferencesHelper.setNotificationDelegate(
+ callingPkg, callingUid, delegate, info.uid);
+ savePolicyFile();
+ }
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
+ @Override
+ public void revokeNotificationDelegate(String callingPkg) {
+ checkCallerIsSameApp(callingPkg);
+ mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
+ savePolicyFile();
+ }
+
+ @Override
+ public String getNotificationDelegate(String callingPkg) {
+ // callable by Settings also
+ checkCallerIsSystemOrSameApp(callingPkg);
+ return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
+ }
+
+ @Override
+ public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
+ checkCallerIsSameApp(callingPkg);
+ final int callingUid = Binder.getCallingUid();
+ UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ try {
+ ApplicationInfo info =
+ mPackageManager.getApplicationInfo(targetPkg,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ user.getIdentifier());
+ if (info != null) {
+ return mPreferencesHelper.isDelegateAllowed(
+ targetPkg, info.uid, callingPkg, callingUid);
+ }
+ } catch (RemoteException e) {
+ // :(
+ }
+ return false;
+ }
+
+ @Override
public void updateNotificationChannelGroupForPackage(String pkg, int uid,
NotificationChannelGroup group) throws RemoteException {
enforceSystemOrSystemUI("Caller not system or systemui");
@@ -4053,20 +4111,21 @@
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
}
- checkCallerIsSystemOrSameApp(pkg);
- checkRestrictedCategories(notification);
-
- final int userId = ActivityManager.handleIncomingUser(callingPid,
- callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
- final UserHandle user = new UserHandle(userId);
if (pkg == null || notification == null) {
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
- // The system can post notifications for any package, let us resolve that.
- final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
+ final int userId = ActivityManager.handleIncomingUser(callingPid,
+ callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
+ final UserHandle user = UserHandle.of(userId);
+
+ // Can throw a SecurityException if the calling uid doesn't have permission to post
+ // as "pkg"
+ final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
+
+ checkRestrictedCategories(notification);
// Fix the notification as best we can.
try {
@@ -4193,17 +4252,28 @@
}
}
- private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
- // The system can post notifications on behalf of any package it wants
- if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
- try {
- return getContext().getPackageManager()
- .getPackageUidAsUser(opPackageName, userId);
- } catch (NameNotFoundException e) {
- /* ignore */
- }
+ @VisibleForTesting
+ int resolveNotificationUid(String callingPkg, String targetPkg,
+ int callingUid, int userId) {
+ // posted from app A on behalf of app A
+ if (isCallerSameApp(targetPkg, callingUid) && TextUtils.equals(callingPkg, targetPkg)) {
+ return callingUid;
}
- return callingUid;
+
+ int targetUid = -1;
+ try {
+ targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ // posted from app A on behalf of app B
+ if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
+ || mPreferencesHelper.isDelegateAllowed(
+ targetPkg, targetUid, callingPkg, callingUid))) {
+ return targetUid;
+ }
+
+ throw new SecurityException("Caller " + callingUid + " cannot post for pkg " + targetPkg);
}
/**
@@ -4222,7 +4292,8 @@
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
synchronized (mNotificationLock) {
- if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
+ if (mNotificationsByKey.get(r.sbn.getKey()) == null
+ && isCallerInstantApp(pkg, callingUid)) {
// Ephemeral apps have some special constraints for notifications.
// They are not allowed to create new notifications however they are allowed to
// update notifications created by the system (e.g. a foreground service
@@ -5149,11 +5220,11 @@
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) { }
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
effect, "Notification (delayed)", record.getAudioAttributes());
}).start();
} else {
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
effect, "Notification", record.getAudioAttributes());
}
return true;
@@ -6282,6 +6353,11 @@
checkCallerIsSameApp(pkg);
}
+ private boolean isCallerAndroid(String callingPkg, int uid) {
+ return isUidSystemOrPhone(uid) && callingPkg != null
+ && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
+ }
+
/**
* Check if the notification is of a category type that is restricted to system use only,
* if so throw SecurityException
@@ -6302,13 +6378,13 @@
}
}
- private boolean isCallerInstantApp(String pkg) {
+ private boolean isCallerInstantApp(String pkg, int callingUid) {
// System is always allowed to act for ephemeral apps.
- if (isCallerSystemOrPhone()) {
+ if (isUidSystemOrPhone(callingUid)) {
return false;
}
- mAppOps.checkPackage(Binder.getCallingUid(), pkg);
+ mAppOps.checkPackage(callingUid, pkg);
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
@@ -6324,7 +6400,10 @@
}
private void checkCallerIsSameApp(String pkg) {
- final int uid = Binder.getCallingUid();
+ checkCallerIsSameApp(pkg, Binder.getCallingUid());
+ }
+
+ private void checkCallerIsSameApp(String pkg, int uid) {
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(
pkg, 0, UserHandle.getCallingUserId());
@@ -6340,6 +6419,24 @@
}
}
+ private boolean isCallerSameApp(String pkg) {
+ try {
+ checkCallerIsSameApp(pkg);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ private boolean isCallerSameApp(String pkg, int uid) {
+ try {
+ checkCallerIsSameApp(pkg, uid);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
private static String callStateToString(int state) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 432d17c..593e7cd 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -66,12 +67,14 @@
public class PreferencesHelper implements RankingConfig {
private static final String TAG = "NotificationPrefHelper";
private static final int XML_VERSION = 1;
+ private static final int UNKNOWN_UID = UserHandle.USER_NULL;
@VisibleForTesting
static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CHANNEL = "channel";
private static final String TAG_GROUP = "channelGroup";
+ private static final String TAG_DELEGATE = "delegate";
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
@@ -82,6 +85,8 @@
private static final String ATT_IMPORTANCE = "importance";
private static final String ATT_SHOW_BADGE = "show_badge";
private static final String ATT_APP_USER_LOCKED_FIELDS = "app_user_locked_fields";
+ private static final String ATT_ENABLED = "enabled";
+ private static final String ATT_USER_ALLOWED = "allowed";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -147,8 +152,7 @@
}
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
- int uid = XmlUtils.readIntAttribute(parser, ATT_UID,
- PackagePreferences.UNKNOWN_UID);
+ int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
if (forRestore) {
@@ -217,6 +221,24 @@
r.channels.put(id, channel);
}
}
+ // Delegate
+ if (TAG_DELEGATE.equals(tagName)) {
+ int delegateId =
+ XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+ String delegateName =
+ XmlUtils.readStringAttribute(parser, ATT_NAME);
+ boolean delegateEnabled = XmlUtils.readBooleanAttribute(
+ parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
+ boolean userAllowed = XmlUtils.readBooleanAttribute(
+ parser, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
+ Delegate d = null;
+ if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(delegateName)) {
+ d = new Delegate(
+ delegateName, delegateId, delegateEnabled, userAllowed);
+ }
+ r.delegate = d;
+ }
+
}
try {
@@ -248,7 +270,7 @@
final String key = packagePreferencesKey(pkg, uid);
synchronized (mPackagePreferencess) {
PackagePreferences
- r = (uid == PackagePreferences.UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+ r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
: mPackagePreferencess.get(key);
if (r == null) {
r = new PackagePreferences();
@@ -265,7 +287,7 @@
Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
}
- if (r.uid == PackagePreferences.UNKNOWN_UID) {
+ if (r.uid == UNKNOWN_UID) {
mRestoredWithoutUids.put(pkg, r);
} else {
mPackagePreferencess.put(key, r);
@@ -357,7 +379,8 @@
|| r.showBadge != DEFAULT_SHOW_BADGE
|| r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS
|| r.channels.size() > 0
- || r.groups.size() > 0;
+ || r.groups.size() > 0
+ || r.delegate != null;
if (hasNonDefaultSettings) {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
@@ -378,6 +401,21 @@
out.attribute(null, ATT_UID, Integer.toString(r.uid));
}
+ if (r.delegate != null) {
+ out.startTag(null, TAG_DELEGATE);
+
+ out.attribute(null, ATT_NAME, r.delegate.mPkg);
+ out.attribute(null, ATT_UID, Integer.toString(r.delegate.mUid));
+ if (r.delegate.mEnabled != Delegate.DEFAULT_ENABLED) {
+ out.attribute(null, ATT_ENABLED, Boolean.toString(r.delegate.mEnabled));
+ }
+ if (r.delegate.mUserAllowed != Delegate.DEFAULT_USER_ALLOWED) {
+ out.attribute(null, ATT_USER_ALLOWED,
+ Boolean.toString(r.delegate.mUserAllowed));
+ }
+ out.endTag(null, TAG_DELEGATE);
+ }
+
for (NotificationChannelGroup group : r.groups.values()) {
group.writeXml(out);
}
@@ -923,16 +961,76 @@
* considered for sentiment adjustments (and thus never show a blocking helper).
*/
public void setAppImportanceLocked(String packageName, int uid) {
- PackagePreferences PackagePreferences = getOrCreatePackagePreferences(packageName, uid);
- if ((PackagePreferences.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
+ PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid);
+ if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
return;
}
- PackagePreferences.lockedAppFields =
- PackagePreferences.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+ prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
updateConfig();
}
+ /**
+ * Returns the delegate for a given package, if it's allowed by the package and the user.
+ */
+ public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+
+ if (prefs == null || prefs.delegate == null) {
+ return null;
+ }
+ if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
+ return null;
+ }
+ return prefs.delegate.mPkg;
+ }
+
+ /**
+ * Used by an app to delegate notification posting privileges to another apps.
+ */
+ public void setNotificationDelegate(String sourcePkg, int sourceUid,
+ String delegatePkg, int delegateUid) {
+ PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid);
+
+ boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
+ Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
+ prefs.delegate = delegate;
+ updateConfig();
+ }
+
+ /**
+ * Used by an app to turn off its notification delegate.
+ */
+ public void revokeNotificationDelegate(String sourcePkg, int sourceUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+ if (prefs != null && prefs.delegate != null) {
+ prefs.delegate.mEnabled = false;
+ updateConfig();
+ }
+ }
+
+ /**
+ * Toggles whether an app can have a notification delegate on behalf of a user.
+ */
+ public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+ if (prefs != null && prefs.delegate != null) {
+ prefs.delegate.mUserAllowed = userAllowed;
+ updateConfig();
+ }
+ }
+
+ /**
+ * Returns whether the given app is allowed on post notifications on behalf of the other given
+ * app.
+ */
+ public boolean isDelegateAllowed(String sourcePkg, int sourceUid,
+ String potentialDelegatePkg, int potentialDelegateUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+
+ return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid);
+ }
+
@VisibleForTesting
void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
if (original.canBypassDnd() != update.canBypassDnd()) {
@@ -994,8 +1092,7 @@
pw.print(" AppSettings: ");
pw.print(r.pkg);
pw.print(" (");
- pw.print(r.uid == PackagePreferences.UNKNOWN_UID ? "UNKNOWN_UID"
- : Integer.toString(r.uid));
+ pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
if (r.importance != DEFAULT_IMPORTANCE) {
pw.print(" importance=");
@@ -1356,8 +1453,6 @@
}
private static class PackagePreferences {
- static int UNKNOWN_UID = UserHandle.USER_NULL;
-
String pkg;
int uid = UNKNOWN_UID;
int importance = DEFAULT_IMPORTANCE;
@@ -1366,7 +1461,37 @@
boolean showBadge = DEFAULT_SHOW_BADGE;
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+ Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
Map<String, NotificationChannelGroup> groups = new ConcurrentHashMap<>();
+
+ public boolean isValidDelegate(String pkg, int uid) {
+ return delegate != null && delegate.isAllowed(pkg, uid);
+ }
+ }
+
+ private static class Delegate {
+ static final boolean DEFAULT_ENABLED = true;
+ static final boolean DEFAULT_USER_ALLOWED = true;
+ String mPkg;
+ int mUid = UNKNOWN_UID;
+ boolean mEnabled = DEFAULT_ENABLED;
+ boolean mUserAllowed = DEFAULT_USER_ALLOWED;
+
+ Delegate(String pkg, int uid, boolean enabled, boolean userAllowed) {
+ mPkg = pkg;
+ mUid = uid;
+ mEnabled = enabled;
+ mUserAllowed = userAllowed;
+ }
+
+ public boolean isAllowed(String pkg, int uid) {
+ if (pkg == null || uid == UNKNOWN_UID) {
+ return false;
+ }
+ return pkg.equals(mPkg)
+ && uid == mUid
+ && (mUserAllowed && mEnabled);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index cf47d4e..bca3ca7 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -40,6 +40,7 @@
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -124,7 +125,8 @@
synchronized (mPackageManagerService.mPackages) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
- mPackageManagerService.mPackages.values(), mPackageManagerService);
+ mPackageManagerService.mPackages.values(), mPackageManagerService,
+ DEBUG_DEXOPT);
// Others: we should optimize this with the (first-)boot compiler-reason.
others = new ArrayList<>(mPackageManagerService.mPackages.values());
others.removeAll(important);
@@ -157,6 +159,24 @@
long spaceAvailableNow = getAvailableSpace();
prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
+
+ if (DEBUG_DEXOPT) {
+ try {
+ // Output some data about the packages.
+ PackageParser.Package lastUsed = Collections.max(important,
+ (pkg1, pkg2) -> Long.compare(
+ pkg1.getLatestForegroundPackageUseTimeInMills(),
+ pkg2.getLatestForegroundPackageUseTimeInMills()));
+ Log.d(TAG, "A/B OTA: lastUsed time = "
+ + lastUsed.getLatestForegroundPackageUseTimeInMills());
+ Log.d(TAG, "A/B OTA: deprioritized packages:");
+ for (PackageParser.Package pkg : others) {
+ Log.d(TAG, " " + pkg.packageName + " - "
+ + pkg.getLatestForegroundPackageUseTimeInMills());
+ }
+ } catch (Exception ignored) {
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 1aea8f0..390c0cc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -164,6 +164,13 @@
public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService) {
+ return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
+ }
+
+ public static List<PackageParser.Package> getPackagesForDexopt(
+ Collection<PackageParser.Package> packages,
+ PackageManagerService packageManagerService,
+ boolean debug) {
ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
LinkedList<PackageParser.Package> result = new LinkedList<>();
ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
@@ -189,14 +196,14 @@
// TODO: add a property to control this?
Predicate<PackageParser.Package> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Looking at historical package use");
}
// Get the package that was used last.
PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
}
long estimatedPreviousSystemUseTime =
@@ -218,7 +225,7 @@
applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
packageManagerService);
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c8bd211..479f427 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -55,7 +55,6 @@
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -99,7 +98,6 @@
import com.android.server.FgThread;
import com.android.server.SystemService;
-import java.lang.reflect.InvocationTargetException;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -120,7 +118,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
-import com.android.internal.R;
public class WallpaperManagerService extends IWallpaperManager.Stub
implements IWallpaperManagerService {
@@ -1544,14 +1541,6 @@
return false;
}
- private Point getDefaultDisplaySize() {
- Point p = new Point();
- WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- Display d = wm.getDefaultDisplay();
- d.getRealSize(p);
- return p;
- }
-
public void setDimensionHints(int width, int height, String callingPackage)
throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
@@ -1564,10 +1553,6 @@
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
- // Make sure it is at least as large as the display.
- Point displaySize = getDefaultDisplaySize();
- width = Math.max(width, displaySize.x);
- height = Math.max(height, displaySize.y);
if (width != wallpaper.width || height != wallpaper.height) {
wallpaper.width = width;
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 8fbc01e..9d686ef 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -119,13 +119,23 @@
private volatile UnicastResponder mUnicastResponder;
public static class RaParams {
+ // Tethered traffic will have the hop limit properly decremented.
+ // Consequently, set the hoplimit greater by one than the upstream
+ // unicast hop limit.
+ //
+ // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the
+ // upstream interface for more correct behaviour.
+ static final byte DEFAULT_HOPLIMIT = 65;
+
public boolean hasDefaultRoute;
+ public byte hopLimit;
public int mtu;
public HashSet<IpPrefix> prefixes;
public HashSet<Inet6Address> dnses;
public RaParams() {
hasDefaultRoute = false;
+ hopLimit = DEFAULT_HOPLIMIT;
mtu = IPV6_MIN_MTU;
prefixes = new HashSet<IpPrefix>();
dnses = new HashSet<Inet6Address>();
@@ -133,6 +143,7 @@
public RaParams(RaParams other) {
hasDefaultRoute = other.hasDefaultRoute;
+ hopLimit = other.hopLimit;
mtu = other.mtu;
prefixes = (HashSet) other.prefixes.clone();
dnses = (HashSet) other.dnses.clone();
@@ -273,10 +284,12 @@
final ByteBuffer ra = ByteBuffer.wrap(mRA);
ra.order(ByteOrder.BIG_ENDIAN);
+ final boolean haveRaParams = (mRaParams != null);
boolean shouldSendRA = false;
try {
- putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute);
+ putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
+ haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
putSlla(ra, mInterface.macAddr.toByteArray());
mRaLength = ra.position();
@@ -287,7 +300,7 @@
//
// putExpandedFlagsOption(ra);
- if (mRaParams != null) {
+ if (haveRaParams) {
putMtu(ra, mRaParams.mtu);
mRaLength = ra.position();
@@ -348,7 +361,7 @@
private static byte asByte(int value) { return (byte) value; }
private static short asShort(int value) { return (short) value; }
- private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute) {
+ private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
/**
Router Advertisement Message Format
@@ -366,11 +379,10 @@
| Options ...
+-+-+-+-+-+-+-+-+-+-+-+-
*/
- final byte DEFAULT_HOPLIMIT = 64;
ra.put(ICMPV6_ND_ROUTER_ADVERT)
.put(asByte(0))
.putShort(asShort(0))
- .put(DEFAULT_HOPLIMIT)
+ .put(hopLimit)
// RFC 4191 "high" preference, iff. advertising a default route.
.put(hasDefaultRoute ? asByte(0x08) : asByte(0))
.putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 0ff124e..a1b3b98 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -65,6 +65,8 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Application;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -195,6 +197,8 @@
IUriGrantsManager mUgm;
@Mock
UriGrantsManagerInternal mUgmInternal;
+ @Mock
+ AppOpsManager mAppOpsManager;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -295,7 +299,8 @@
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
mGroupHelper, mAm, mAppUsageStats,
- mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal);
+ mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
+ mAppOpsManager);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -531,7 +536,7 @@
mBinderService.createNotificationChannels(
PKG, new ParceledListSlice(Arrays.asList(channel)));
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -549,7 +554,7 @@
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -578,7 +583,7 @@
StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
// The first time a foreground service notification is shown, we allow the channel
@@ -600,7 +605,7 @@
sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
// The second time it is shown, we keep the user's preference.
@@ -631,7 +636,7 @@
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -645,7 +650,7 @@
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -667,7 +672,7 @@
final StatusBarNotification sbn =
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
sbn.getNotification().category = category;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
waitForIdle();
@@ -691,7 +696,7 @@
final StatusBarNotification sbn =
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
sbn.getNotification().category = category;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
waitForIdle();
@@ -714,7 +719,7 @@
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().category = category;
try {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
fail("Calls from non system apps should not allow use of restricted categories");
} catch (SecurityException e) {
@@ -746,7 +751,7 @@
@Test
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
@@ -756,7 +761,7 @@
@Test
public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
waitForIdle();
@@ -768,10 +773,10 @@
@Test
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
waitForIdle();
@@ -788,7 +793,7 @@
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
NotificationRecord r = generateNotificationRecord(null);
final StatusBarNotification sbn = r.sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelNotificationsFromListener(null, null);
waitForIdle();
@@ -801,7 +806,7 @@
@Test
public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -816,7 +821,7 @@
final NotificationRecord n = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId());
waitForIdle();
@@ -839,9 +844,9 @@
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group1", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
waitForIdle();
@@ -854,7 +859,7 @@
public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
for (int i = 0; i < 10; i++) {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
@@ -873,17 +878,17 @@
mTestNotificationChannel, 2, "group1", false);
// fully post parent notification
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
waitForIdle();
// enqueue the child several times
for (int i = 0; i < 10; i++) {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
}
// make the parent a child, which will cancel the child notification
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
parentAsChild.sbn.getUserId());
waitForIdle();
@@ -895,7 +900,7 @@
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -909,7 +914,7 @@
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
waitForIdle();
@@ -922,7 +927,7 @@
@Test
public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(null, sbn.getUserId());
waitForIdle();
@@ -935,7 +940,7 @@
@Test
public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
// Null pkg is how we signal a user switch.
mBinderService.cancelAllNotifications(null, sbn.getUserId());
@@ -950,7 +955,7 @@
public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -1037,7 +1042,7 @@
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
sbn.getUserId());
@@ -1052,10 +1057,10 @@
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags =
Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
waitForIdle();
@@ -1145,21 +1150,21 @@
// should not be returned
final NotificationRecord group2 = generateNotificationRecord(
mTestNotificationChannel, 2, "group2", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId());
waitForIdle();
// should not be returned
final NotificationRecord nonGroup = generateNotificationRecord(
mTestNotificationChannel, 3, null, false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId());
waitForIdle();
// same group, child, should be returned
final NotificationRecord group1Child = generateNotificationRecord(
mTestNotificationChannel, 4, "group1", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null, group1Child.sbn.getId(),
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null, group1Child.sbn.getId(),
group1Child.sbn.getNotification(), group1Child.sbn.getUserId());
waitForIdle();
@@ -1216,7 +1221,7 @@
public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -1333,7 +1338,7 @@
new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null, tv).getNotification(), 0);
verify(mPreferencesHelper, times(1)).getNotificationChannel(
anyString(), anyInt(), eq("foo"), anyBoolean());
@@ -1348,7 +1353,7 @@
mTestNotificationChannel);
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null, tv).getNotification(), 0);
verify(mPreferencesHelper, times(1)).getNotificationChannel(
anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
@@ -1879,7 +1884,7 @@
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
waitForIdle();
@@ -1892,7 +1897,7 @@
final NotificationRecord record = generateNotificationRecord(
mTestNotificationChannel, 2, null, false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId());
waitForIdle();
@@ -1904,7 +1909,7 @@
final NotificationRecord parent = generateNotificationRecord(
mTestNotificationChannel, 2, "group", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
waitForIdle();
@@ -2378,12 +2383,12 @@
@Test
public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
String preOPkg = PKG_N_MR1;
- int preOUid = 145;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt()))
.thenReturn(legacy);
- when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())).thenReturn(preOUid);
+ when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt()))
+ .thenReturn(Binder.getCallingUid());
getContext().setMockPackageManager(mPackageManagerClient);
Notification.Builder nb = new Notification.Builder(mContext,
@@ -2393,12 +2398,13 @@
.setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
- StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
- 0, nb.build(), new UserHandle(preOUid), null, 0);
+ StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag",
+ Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
- mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
- sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
+ sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
+
assertEquals(IMPORTANCE_LOW,
mService.getNotificationRecord(sbn.getKey()).getImportance());
@@ -2408,8 +2414,8 @@
.setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
- sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
- 0, nb.build(), new UserHandle(preOUid), null, 0);
+ sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", Binder.getCallingUid(),
+ 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -3360,7 +3366,7 @@
}
@Test
- public void testMybeRecordInterruptionLocked_doesNotRecordTwice()
+ public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
throws RemoteException {
final NotificationRecord r = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
@@ -3373,4 +3379,78 @@
verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
anyString(), anyString(), anyInt());
}
+
+ @Test
+ public void testResolveNotificationUid_sameApp() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = Binder.getCallingUid();
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
+
+ assertEquals(info.uid, actualUid);
+ }
+
+ @Test
+ public void testResolveNotificationUid_sameAppWrongPkg() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = Binder.getCallingUid();
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ try {
+ mService.resolveNotificationUid("caller", "other", info.uid, 0);
+ fail("Incorrect pkg didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = 1356347;
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ try {
+ mService.resolveNotificationUid("caller", "caller", 9, 0);
+ fail("Incorrect uid didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testResolveNotificationUid_delegateAllowed() throws Exception {
+ int expectedUid = 123;
+
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
+ .thenReturn(true);
+
+ assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
+ }
+
+ @Test
+ public void testResolveNotificationUid_androidAllowed() throws Exception {
+ int expectedUid = 123;
+
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
+ // no delegate
+
+ assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
+ }
+
+ @Test
+ public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
+ // no delegate
+
+ try {
+ mService.resolveNotificationUid("caller", "target", 9, 0);
+ fail("Incorrect uid didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 73adf25..750345b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -123,7 +123,6 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- UserHandle user = UserHandle.ALL;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
@@ -176,11 +175,6 @@
.build();
}
- private NotificationChannel getDefaultChannel() {
- return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- IMPORTANCE_LOW);
- }
-
private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
String... channelIds)
throws Exception {
@@ -1787,4 +1781,159 @@
mHelper.setEnabled(PKG_N_MR1, 1000, true);
assertEquals(3, mHelper.getBlockedAppCount(0));
}
+
+ @Test
+ public void testSetNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testRevokeNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() {
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testToggleNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testToggleNotificationDelegate_noDelegateExistsNoCrash() {
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_noSource() {
+ assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_noDelegate() {
+ mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_delegateDisabledByApp() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_wrongDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_delegateDisabledByUser() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testIsDelegateAllowed() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+
+ assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testDelegateXml_noDelegate() throws Exception {
+ mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_delegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_disabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_userDisabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ // appears disabled
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ // but was loaded and can be toggled back on
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_entirelyDisabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ // appears disabled
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
}