Merge "Updated haptic effect for success" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 35a2689..1789d1d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -805,6 +805,7 @@
Landroid/content/pm/PackageParser$Package;->mPreferredOrder:I
Landroid/content/pm/PackageParser$Package;->mSharedUserId:Ljava/lang/String;
Landroid/content/pm/PackageParser$Package;->mSharedUserLabel:I
+Landroid/content/pm/PackageParser$Package;->mSigningDetails:Landroid/content/pm/PackageParser$SigningDetails;
Landroid/content/pm/PackageParser$Package;->mVersionCode:I
Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String;
Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
@@ -821,6 +822,7 @@
Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo;
Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
+Landroid/content/pm/PackageParser$SigningDetails;->signatures:[Landroid/content/pm/Signature;
Landroid/content/pm/PackageParser;-><init>()V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
@@ -884,6 +886,7 @@
Landroid/content/res/DrawableCache;-><init>()V
Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
Landroid/content/res/ObbInfo;->salt:[B
+Landroid/content/res/Resources$Theme;->mThemeImpl:Landroid/content/res/ResourcesImpl$ThemeImpl;
Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
@@ -1465,6 +1468,7 @@
Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getCaptureSession()Ljava/lang/Integer;
Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getData()[B
+Landroid/media/soundtrigger/SoundTriggerManager;->isRecognitionActive(Ljava/util/UUID;)Z
Landroid/media/soundtrigger/SoundTriggerManager;->loadSoundModel(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;)I
Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/app/PendingIntent;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/os/Bundle;Landroid/content/ComponentName;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
@@ -2282,6 +2286,7 @@
Landroid/renderscript/RenderScriptCacheDir;->mCacheDir:Ljava/io/File;
Landroid/renderscript/RenderScriptCacheDir;->setupDiskCache(Ljava/io/File;)V
Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J
+Landroid/security/keystore/recovery/RecoveryController;->getRecoveryStatus(Ljava/lang/String;Ljava/lang/String;)I
Landroid/security/keystore/recovery/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V
Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 97c9fa5..7338bfe 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -236,6 +236,17 @@
int userId, Intent[] intents, Bundle bOptions);
/**
+ * Start activity {@code intent} without calling user-id check.
+ *
+ * - DO NOT call it with the calling UID cleared.
+ * - The caller must do the calling user ID check.
+ *
+ * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
+ */
+ public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ Intent intent, @Nullable Bundle options, int userId);
+
+ /**
* Get the procstate for the UID. The return value will be between
* {@link ActivityManager#MIN_PROCESS_STATE} and {@link ActivityManager#MAX_PROCESS_STATE}.
* Note if the UID doesn't exist, it'll return {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 725f240..327d4fe 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2722,7 +2722,40 @@
* @hide
*/
public static boolean areRemoteViewsChanged(Builder first, Builder second) {
- return !first.usesStandardHeader() || !second.usesStandardHeader();
+ if (!Objects.equals(first.usesStandardHeader(), second.usesStandardHeader())) {
+ return true;
+ }
+
+ if (areRemoteViewsChanged(first.mN.contentView, second.mN.contentView)) {
+ return true;
+ }
+ if (areRemoteViewsChanged(first.mN.bigContentView, second.mN.bigContentView)) {
+ return true;
+ }
+ if (areRemoteViewsChanged(first.mN.headsUpContentView, second.mN.headsUpContentView)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean areRemoteViewsChanged(RemoteViews first, RemoteViews second) {
+ if (first == null && second == null) {
+ return false;
+ }
+ if (first == null && second != null || first != null && second == null) {
+ return true;
+ }
+
+ if (!Objects.equals(first.getLayoutId(), second.getLayoutId())) {
+ return true;
+ }
+
+ if (!Objects.equals(first.getSequenceNumber(), second.getSequenceNumber())) {
+ return true;
+ }
+
+ return false;
}
/**
diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java
index 20c1390..746beaf 100644
--- a/core/java/android/app/slice/SliceMetrics.java
+++ b/core/java/android/app/slice/SliceMetrics.java
@@ -18,9 +18,11 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.metrics.LogMaker;
import android.net.Uri;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Metrics interface for slices.
@@ -34,24 +36,38 @@
private static final String TAG = "SliceMetrics";
private MetricsLogger mMetricsLogger;
+ private LogMaker mLogMaker;
/**
* An object to be used throughout the life of a slice to register events.
*/
public SliceMetrics(@NonNull Context context, @NonNull Uri uri) {
mMetricsLogger = new MetricsLogger();
+ mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
+ mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_AUTHORITY, uri.getAuthority());
+ mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_PATH, uri.getPath());
}
/**
* To be called whenever the slice becomes visible to the user.
*/
public void logVisible() {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_OPEN);
+ mMetricsLogger.write(mLogMaker);
+ }
}
/**
* To be called whenever the slice becomes invisible to the user.
*/
public void logHidden() {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_CLOSE);
+ mMetricsLogger.write(mLogMaker);
+ }
}
/**
@@ -68,5 +84,12 @@
* @param subSlice The URI of the sub-slice that is the subject of the interaction.
*/
public void logTouch(int actionType, @NonNull Uri subSlice) {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .addTaggedData(MetricsEvent.FIELD_SUBSLICE_AUTHORITY, subSlice.getAuthority())
+ .addTaggedData(MetricsEvent.FIELD_SUBSLICE_PATH, subSlice.getPath());
+ mMetricsLogger.write(mLogMaker);
+ }
}
}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index ae1c207..ba7710b 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
@@ -42,10 +43,10 @@
String callingPackage, String packageName, in UserHandle user);
ActivityInfo resolveActivity(
String callingPackage, in ComponentName component, in UserHandle user);
- void startActivityAsUser(String callingPackage,
+ void startActivityAsUser(in IApplicationThread caller, String callingPackage,
in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- void showAppDetailsAsUser(
+ void showAppDetailsAsUser(in IApplicationThread caller,
String callingPackage, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
boolean isPackageEnabled(String callingPackage, String packageName, in UserHandle user);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8717601..fa423e2 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -548,7 +548,8 @@
Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
}
try {
- mService.startActivityAsUser(mContext.getPackageName(),
+ mService.startActivityAsUser(mContext.getIApplicationThread(),
+ mContext.getPackageName(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -568,7 +569,8 @@
Rect sourceBounds, Bundle opts) {
logErrorForInvalidProfileAccess(user);
try {
- mService.showAppDetailsAsUser(mContext.getPackageName(),
+ mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
+ mContext.getPackageName(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fdae191..9e56d14 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1785,6 +1785,12 @@
public static final int USER_SETUP_PERSONALIZATION_STARTED = 1;
/**
+ * User has snoozed personalization and will complete it later.
+ * @hide
+ */
+ public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2;
+
+ /**
* User has completed setup personalization.
* @hide
*/
@@ -1795,6 +1801,7 @@
@IntDef({
USER_SETUP_PERSONALIZATION_NOT_STARTED,
USER_SETUP_PERSONALIZATION_STARTED,
+ USER_SETUP_PERSONALIZATION_PAUSED,
USER_SETUP_PERSONALIZATION_COMPLETE
})
public @interface UserSetupPersonalization {}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 309fa4a..510626b 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,10 @@
package android.service.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
@@ -68,6 +72,7 @@
public static final int SOURCE_STAR = 2;
public static final int MAX_SOURCE = SOURCE_STAR;
private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
+ private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR;
public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
@@ -93,13 +98,10 @@
private static final boolean DEFAULT_ALLOW_REMINDERS = false;
private static final boolean DEFAULT_ALLOW_EVENTS = false;
private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
private static final boolean DEFAULT_CHANNELS_BYPASSING_DND = false;
- private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
- Policy.getAllSuppressedVisualEffects();
+ private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS = 0;
- public static final int XML_VERSION = 7;
+ public static final int XML_VERSION = 8;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -151,12 +153,10 @@
public boolean allowMessages = DEFAULT_ALLOW_MESSAGES;
public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
- public int allowCallsFrom = DEFAULT_SOURCE;
+ public int allowCallsFrom = DEFAULT_CALLS_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
public int user = UserHandle.USER_SYSTEM;
public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
- public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
- public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND;
public int version;
@@ -185,8 +185,6 @@
automaticRules.put(ids[i], rules[i]);
}
}
- allowWhenScreenOff = source.readInt() == 1;
- allowWhenScreenOn = source.readInt() == 1;
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
allowSystem = source.readInt() == 1;
@@ -219,8 +217,6 @@
} else {
dest.writeInt(0);
}
- dest.writeInt(allowWhenScreenOff ? 1 : 0);
- dest.writeInt(allowWhenScreenOn ? 1 : 0);
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
dest.writeInt(allowSystem ? 1 : 0);
@@ -242,8 +238,6 @@
.append(",allowMessages=").append(allowMessages)
.append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
.append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
- .append(",allowWhenScreenOff=").append(allowWhenScreenOff)
- .append(",allowWhenScreenOn=").append(allowWhenScreenOn)
.append(",suppressedVisualEffects=").append(suppressedVisualEffects)
.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
.append(",automaticRules=").append(automaticRules)
@@ -289,12 +283,6 @@
if (allowMessagesFrom != to.allowMessagesFrom) {
d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom);
}
- if (allowWhenScreenOff != to.allowWhenScreenOff) {
- d.addLine("allowWhenScreenOff", allowWhenScreenOff, to.allowWhenScreenOff);
- }
- if (allowWhenScreenOn != to.allowWhenScreenOn) {
- d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
- }
if (suppressedVisualEffects != to.suppressedVisualEffects) {
d.addLine("suppressedVisualEffects", suppressedVisualEffects,
to.suppressedVisualEffects);
@@ -404,8 +392,6 @@
&& other.allowMessagesFrom == allowMessagesFrom
&& other.allowReminders == allowReminders
&& other.allowEvents == allowEvents
- && other.allowWhenScreenOff == allowWhenScreenOff
- && other.allowWhenScreenOn == allowWhenScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule)
@@ -418,7 +404,7 @@
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
- allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+ user, automaticRules, manualRule,
suppressedVisualEffects, areChannelsBypassingDnd);
}
@@ -472,6 +458,7 @@
final ZenModeConfig rt = new ZenModeConfig();
rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
+ boolean readSuppressedEffects = false;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
@@ -502,17 +489,33 @@
rt.allowCallsFrom = DEFAULT_SOURCE;
rt.allowMessagesFrom = DEFAULT_SOURCE;
}
- // continue to read even though we now have suppressedVisualEffects, in case
- // we need to revert to users' previous settings
- rt.allowWhenScreenOff =
- safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
- rt.allowWhenScreenOn =
- safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
rt.allowAlarms = safeBoolean(parser, ALLOW_ATT_ALARMS, DEFAULT_ALLOW_ALARMS);
rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
DEFAULT_ALLOW_MEDIA);
rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
- } else if (DISALLOW_TAG.equals(tag)) {
+
+ // migrate old suppressed visual effects fields, if they still exist in the xml
+ Boolean allowWhenScreenOff = unsafeBoolean(parser, ALLOW_ATT_SCREEN_OFF);
+ if (allowWhenScreenOff != null) {
+ readSuppressedEffects = true;
+ if (allowWhenScreenOff) {
+ rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ }
+ }
+ Boolean allowWhenScreenOn = unsafeBoolean(parser, ALLOW_ATT_SCREEN_ON);
+ if (allowWhenScreenOn != null) {
+ readSuppressedEffects = true;
+ if (allowWhenScreenOn) {
+ rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ }
+ if (readSuppressedEffects) {
+ Slog.d(TAG, "Migrated visual effects to " + rt.suppressedVisualEffects);
+ }
+ } else if (DISALLOW_TAG.equals(tag) && !readSuppressedEffects) {
+ // only read from suppressed visual effects field if we haven't just migrated
+ // the values from allowOn/allowOff, lest we wipe out those settings
rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
@@ -552,8 +555,6 @@
out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
- out.attribute(null, ALLOW_ATT_SCREEN_OFF, Boolean.toString(allowWhenScreenOff));
- out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowWhenScreenOn));
out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia));
out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
@@ -673,6 +674,12 @@
return source >= SOURCE_ANYONE && source <= MAX_SOURCE;
}
+ private static Boolean unsafeBoolean(XmlPullParser parser, String att) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return null;
+ return Boolean.parseBoolean(val);
+ }
+
private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
final String val = parser.getAttributeValue(null, att);
return safeBoolean(val, defValue);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1c2e43e..6bacdfe 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -901,7 +901,7 @@
* Refreshes this info with the latest state of the view it represents, and request new
* data be added by the View.
*
- * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
+ * @param extraDataKey The extra data requested. Data that must be requested
* with this mechanism is generally expensive to retrieve, so should only be
* requested when needed. See
* {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ced66cd..e7c3a47 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1373,7 +1373,7 @@
* indicator. To animate the visual position to the target value, use
* {@link #setProgress(int, boolean)}}.
*
- * @param progress the new progress, between 0 and {@link #getMax()}
+ * @param progress the new progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1392,7 +1392,7 @@
* Animation does not affect the result of {@link #getProgress()}, which
* will return the target value immediately after this method is called.
*
- * @param progress the new progress value, between 0 and {@link #getMax()}
+ * @param progress the new progress value, between {@link #getMin()} and {@link #getMax()}
* @param animate {@code true} to animate between the current and target
* values or {@code false} to not animate
*/
@@ -1425,7 +1425,8 @@
* anything if the progress bar is in indeterminate mode.
* </p>
*
- * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
+ * @param secondaryProgress the new secondary progress, between {@link #getMin()} and
+ * {@link #getMax()}
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
* @see #getSecondaryProgress()
@@ -1455,7 +1456,7 @@
* <p>Get the progress bar's current level of progress. Return 0 when the
* progress bar is in indeterminate mode.</p>
*
- * @return the current progress, between 0 and {@link #getMax()}
+ * @return the current progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1472,7 +1473,7 @@
* <p>Get the progress bar's current level of secondary progress. Return 0 when the
* progress bar is in indeterminate mode.</p>
*
- * @return the current secondary progress, between 0 and {@link #getMax()}
+ * @return the current secondary progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1990,7 +1991,8 @@
if (!isIndeterminate()) {
AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(
- AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, 0, getMax(), getProgress());
+ AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
+ getProgress());
info.setRangeInfo(rangeInfo);
}
}
diff --git a/core/res/res/drawable/ic_dnd_block_notifications.xml b/core/res/res/drawable/ic_dnd_block_notifications.xml
new file mode 100644
index 0000000..4983614
--- /dev/null
+++ b/core/res/res/drawable/ic_dnd_block_notifications.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportWidth="40.0"
+ android:viewportHeight="40.0">
+ <path
+ android:pathData="M34,20H2c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h32c1.1,0 2,0.9 2,2v12C36,19.1 35.1,20 34,20z"
+ android:fillColor="#FBBC04"/>
+ <path
+ android:pathData="M4.63,10L4.63,10c-0.83,0 -1.5,-0.67 -1.5,-1.5v0C3.12,7.67 3.8,7 4.62,7h0c0.82,0 1.5,0.67 1.5,1.5v0C6.12,9.33 5.45,10 4.63,10z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M8.62,7.5h9.5v2h-9.5z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M3.12,15h24v2h-24z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M3.12,12h17.5v2h-17.5z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M33.59,6.41m-5.78,0a5.78,5.78 0,1 1,11.56 0a5.78,5.78 0,1 1,-11.56 0"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M33.5,0C29.91,0 27,2.91 27,6.5s2.91,6.5 6.5,6.5S40,10.09 40,6.5S37.09,0 33.5,0zM33.5,11.7c-2.87,0 -5.2,-2.33 -5.2,-5.2s2.33,-5.2 5.2,-5.2s5.2,2.33 5.2,5.2S36.37,11.7 33.5,11.7z"
+ android:fillColor="#4285F4"/>
+ <path
+ android:pathData="M30.25,5.85h6.5v1.3h-6.5z"
+ android:fillColor="#4285F4"/>
+</vector>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5298e5b..c3ab1a6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2555,6 +2555,7 @@
<java-symbol type="drawable" name="ic_storage_48dp" />
<java-symbol type="drawable" name="ic_usb_48dp" />
<java-symbol type="drawable" name="ic_zen_24dp" />
+ <java-symbol type="drawable" name="ic_dnd_block_notifications" />
<!-- Floating toolbar -->
<java-symbol type="id" name="floating_toolbar_menu_item_image" />
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 3a71851..ba8173e 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -19,7 +19,7 @@
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
<zen version="7">
- <allow alarms="true" media="true" system="false" calls="false" messages="false"
+ <allow alarms="true" media="true" system="false" calls="false" callsFrom="2" messages="false"
reminders="false" events="false" />
<!-- all visual effects that exist as of P -->
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index be7d663..569de76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -40,7 +40,6 @@
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
- SkSafeUnref(mColorFilter);
setTransform(nullptr);
mRenderState.unregisterDeferredLayerUpdater(this);
destroyLayer();
@@ -67,8 +66,11 @@
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
mAlpha = PaintUtils::getAlphaDirect(paint);
mMode = PaintUtils::getBlendModeDirect(paint);
- SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
- SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+ if (paint) {
+ mColorFilter = paint->refColorFilter();
+ } else {
+ mColorFilter.reset();
+ }
}
void DeferredLayerUpdater::apply() {
@@ -143,7 +145,7 @@
#endif
mSurfaceTexture->getTransformMatrix(transform);
- updateLayer(forceFilter, transform);
+ updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
}
}
@@ -153,17 +155,19 @@
Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
- updateLayer(false, identityMatrix.data);
+ updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
vkLayer->updateTexture();
}
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
+ android_dataspace dataspace) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
+ mLayer->setDataSpace(dataspace);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9dc029f..fe3ee7a 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
#include <cutils/compiler.h>
#include <gui/GLConsumer.h>
+#include <system/graphics.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -41,7 +42,7 @@
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode, bool blend)>
CreateLayerFn;
ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
@@ -96,7 +97,7 @@
void detachSurfaceTexture();
- void updateLayer(bool forceFilter, const float* textureTransform);
+ void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
void destroyLayer();
@@ -109,7 +110,7 @@
int mWidth = 0;
int mHeight = 0;
bool mBlend = false;
- SkColorFilter* mColorFilter = nullptr;
+ sk_sp<SkColorFilter> mColorFilter;
int mAlpha = 255;
SkBlendMode mMode = SkBlendMode::kSrcOver;
sp<GLConsumer> mSurfaceTexture;
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 32a3014..42ae29d 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,7 +32,7 @@
namespace uirenderer {
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 1b09191..28749a0 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -32,7 +32,7 @@
class GlLayer : public Layer {
public:
GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
uint32_t getWidth() const override { return texture.mWidth; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 86950d5..fb8f033 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,34 +18,58 @@
#include "renderstate/RenderState.h"
-#include <SkColorFilter.h>
+#include <SkToSRGBColorFilter.h>
namespace android {
namespace uirenderer {
-Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
, mApi(api)
- , colorFilter(nullptr)
+ , mColorFilter(colorFilter)
, alpha(alpha)
, mode(mode) {
// TODO: This is a violation of Android's typical ref counting, but it
// preserves the old inc/dec ref locations. This should be changed...
incStrong(nullptr);
-
+ buildColorSpaceWithFilter();
renderState.registerLayer(this);
}
Layer::~Layer() {
- SkSafeUnref(colorFilter);
-
mRenderState.unregisterLayer(this);
}
-void Layer::setColorFilter(SkColorFilter* filter) {
- SkRefCnt_SafeAssign(colorFilter, filter);
+void Layer::setColorFilter(sk_sp<SkColorFilter> filter) {
+ if (filter != mColorFilter) {
+ mColorFilter = filter;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::setDataSpace(android_dataspace dataspace) {
+ if (dataspace != mCurrentDataspace) {
+ mCurrentDataspace = dataspace;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::buildColorSpaceWithFilter() {
+ sk_sp<SkColorFilter> colorSpaceFilter;
+ sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace);
+ if (colorSpace && !colorSpace->isSRGB()) {
+ colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+ }
+
+ if (mColorFilter && colorSpaceFilter) {
+ mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter);
+ } else if (colorSpaceFilter) {
+ mColorSpaceWithFilter = colorSpaceFilter;
+ } else {
+ mColorSpaceWithFilter = mColorFilter;
+ }
}
void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6921381..89bcddc 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,8 @@
#include <GpuMemoryTracker.h>
#include <utils/RefBase.h>
+#include <SkColorFilter.h>
+#include <SkColorSpace.h>
#include <SkBlendMode.h>
#include <SkPaint.h>
@@ -72,9 +74,15 @@
inline SkBlendMode getMode() const { return mode; }
- inline SkColorFilter* getColorFilter() const { return colorFilter; }
+ inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
- void setColorFilter(SkColorFilter* filter);
+ void setColorFilter(sk_sp<SkColorFilter> filter);
+
+ void setDataSpace(android_dataspace dataspace);
+
+ void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+ inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
inline mat4& getTexTransform() { return texTransform; }
@@ -87,18 +95,30 @@
void postDecStrong();
protected:
- Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+ Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha,
SkBlendMode mode);
RenderState& mRenderState;
private:
+ void buildColorSpaceWithFilter();
+
Api mApi;
/**
* Color filter used to draw this layer. Optional.
*/
- SkColorFilter* colorFilter;
+ sk_sp<SkColorFilter> mColorFilter;
+
+ /**
+ * Colorspace of the contents of the layer. Optional.
+ */
+ android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN;
+
+ /**
+ * A color filter that is the combination of the mColorFilter and mColorSpace. Optional.
+ */
+ sk_sp<SkColorFilter> mColorSpaceWithFilter;
/**
* Indicates raster data backing the layer is scaled, requiring filtration.
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index f23f472..e9664d0 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -28,7 +28,7 @@
class VkLayer : public Layer {
public:
VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
, mWidth(layerWidth)
, mHeight(layerHeight)
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 293e45f..4f16ddb 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -51,8 +51,13 @@
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
- GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
- externalTexture);
+ // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
+ // expose that info we use it as our default. Further, given that we only use this texture
+ // as a source this will not impact how Skia uses the texture. The only potential affect
+ // this is anticipated to have is that for some format types if we are not bound as an OES
+ // texture we may get invalid results for SKP capture if we read back the texture.
+ externalTexture.fFormat = GL_RGBA8;
+ GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, nullptr);
} else {
@@ -82,7 +87,7 @@
SkPaint paint;
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
- paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
+ paint.setColorFilter(layer->getColorSpaceWithFilter());
const bool nonIdentityMatrix = !matrix.isIdentity();
if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 74cfb28..d732a46 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -152,7 +152,7 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) {
GlLayer* layer =
new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
layer->generateTexture();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9e73046..d66cba1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -147,6 +147,7 @@
GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
if (cachedContext.get() != currentContext) {
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers (context changed)");
cachedContext->flush();
}
cachedContext.reset(SkSafeRef(currentContext));
@@ -155,6 +156,7 @@
}
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers");
cachedContext->flush();
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 6530074..5825060 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,8 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+ bool blend) {
return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
}
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 876af47..f96001e 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -123,7 +123,8 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+ bool blend) {
GlLayer* layer =
new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
Caches::getInstance().textureState().activateTexture(0);
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index b99854e..02ac97e 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -75,7 +75,7 @@
layerUpdater->setTransform(&transform);
// updateLayer so it's ready to draw
- layerUpdater->updateLayer(true, Matrix4::identity().data);
+ layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
static_cast<GlLayer*>(layerUpdater->backingLayer())
->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index b8b5050..f29830f 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,7 @@
// push the deferred updates to the layer
Matrix4 scaledMatrix;
scaledMatrix.loadScale(0.5, 0.5, 0.0);
- layerUpdater->updateLayer(true, scaledMatrix.data);
+ layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index c2af867..75740e8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,6 +16,8 @@
#include "Color.h"
+
+#include <utils/Log.h>
#include <cmath>
namespace android {
@@ -53,5 +55,57 @@
return false;
}
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+
+ SkColorSpace::Gamut gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkColorSpace::kSRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkColorSpace::kRec2020_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ gamut = SkColorSpace::kAdobeRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ case HAL_DATASPACE_STANDARD_BT470M:
+ case HAL_DATASPACE_STANDARD_FILM:
+ default:
+ ALOGW("Unsupported Gamut: %d", dataspace);
+ return nullptr;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ default:
+ ALOGW("Unsupported Gamma: %d", dataspace);
+ return nullptr;
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 7ac0d96..2bec1f5 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
#define COLOR_H
#include <math.h>
+#include <system/graphics.h>
#include <SkColor.h>
#include <SkColorSpace.h>
@@ -111,6 +112,8 @@
// approximated with the native sRGB transfer function. This method
// returns true for sRGB, gamma 2.2 and Display P3 for instance
bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1d3e521..32aafea 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 164;
+ private static final int SETTINGS_VERSION = 165;
private final int mUserId;
@@ -3710,17 +3710,7 @@
}
if (currentVersion == 162) {
- // Version 162: Add a gesture for silencing phones
- final SettingsState settings = getGlobalSettingsLocked();
- final Setting currentSetting = settings.getSettingLocked(
- Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
- if (!currentSetting.isNull()
- && TextUtils.equals("0", currentSetting.getValue())) {
- settings.insertSettingLocked(
- Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
- }
-
+ // Version 162: REMOVED: Add a gesture for silencing phones
currentVersion = 163;
}
@@ -3742,6 +3732,21 @@
currentVersion = 164;
}
+ if (currentVersion == 164) {
+ // Version 164: Add a gesture for silencing phones
+ final SettingsState settings = getGlobalSettingsLocked();
+ final Setting currentSetting = settings.getSettingLocked(
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
+ if (!currentSetting.isNull()
+ && TextUtils.equals("0", currentSetting.getValue())) {
+ settings.insertSettingLocked(
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 165;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index c464ba6..93adaa0 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -21,9 +21,9 @@
<item>
<inset
android:insetLeft="0dp"
- android:insetTop="7dp"
+ android:insetTop="8dp"
android:insetRight="0dp"
- android:insetBottom="5dp">
+ android:insetBottom="8dp">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<stroke android:width="1dp" android:color="@color/smart_reply_button_stroke" />
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index 98e6e82..a490c4b 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -26,7 +26,7 @@
android:paddingVertical="@dimen/smart_reply_button_padding_vertical"
android:background="@drawable/smart_reply_button_background"
android:gravity="center"
- android:fontFamily="sans-serif-medium"
+ android:fontFamily="roboto-medium"
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
diff --git a/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
new file mode 100644
index 0000000..eff9b36
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
@@ -0,0 +1,34 @@
+<!--
+ Copyright 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.
+-->
+
+<!-- Extends Framelayout -->
+<com.android.systemui.statusbar.DndSuppressingNotificationsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/hidden_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ <TextView
+ android:id="@+id/hidden_notifications"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="64dp"
+ android:paddingTop="28dp"
+ android:gravity="top|center_horizontal"
+ android:textColor="?attr/wallpaperTextColor"
+ android:textSize="16sp"
+ android:text="@string/dnd_suppressing_shade_text"/>
+</com.android.systemui.statusbar.DndSuppressingNotificationsView>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 438d2f5..eb71911 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -930,12 +930,13 @@
<!-- Home button padding for sizing -->
<dimen name="home_padding">16dp</dimen>
- <!-- Smart reply button -->
+ <!-- Smart reply button. Total height 48dp, visible height 32dp. -->
<dimen name="smart_reply_button_spacing">8dp</dimen>
- <dimen name="smart_reply_button_padding_vertical">10dp</dimen>
- <dimen name="smart_reply_button_padding_horizontal_single_line">16dp</dimen>
- <dimen name="smart_reply_button_padding_horizontal_double_line">16dp</dimen>
- <dimen name="smart_reply_button_min_height">32dp</dimen>
+ <dimen name="smart_reply_button_padding_vertical">14dp</dimen>
+ <!-- Note: The following two paddings need to be different until b/78876518 is fixed. -->
+ <dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
+ <dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
+ <dimen name="smart_reply_button_min_height">48dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 697ab06..50e7b5c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
<string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
+ <!-- Content description of the Trusted Face icon for accessibility. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_scanning_face">Scanning face</string>
<!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
<string name="accessibility_send_smart_reply">Send</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
@@ -1062,7 +1064,7 @@
<string name="manage_notifications_text">Manage notifications</string>
<!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
- <string name="dnd_suppressing_shade_text">Do Not Disturb is hiding notifications</string>
+ <string name="dnd_suppressing_shade_text">Notifications hidden by Do Not Disturb</string>
<!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
<string name="media_projection_action_text">Start now</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
new file mode 100644
index 0000000..db3a02d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.android.systemui.statusbar;
+
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.IntegerRes;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
+
+public class DndSuppressingNotificationsView extends StackScrollerDecorView {
+
+ private TextView mText;
+ private @StringRes int mTextId = R.string.dnd_suppressing_shade_text;
+
+ public DndSuppressingNotificationsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mText.setText(mTextId);
+ }
+
+ @Override
+ protected View findContentView() {
+ return findViewById(R.id.hidden_container);
+ }
+
+ @Override
+ protected View findSecondaryView() {
+ return null;
+ }
+
+ public void setColor(@ColorInt int color) {
+ mText.setTextColor(color);
+ }
+
+ public void setOnContentClickListener(OnClickListener listener) {
+ mText.setOnClickListener(listener);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mText = findViewById(R.id.hidden_notifications);
+ }
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new DndSuppressingViewState();
+ }
+
+ public class DndSuppressingViewState extends ExpandableViewState {
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof DndSuppressingNotificationsView) {
+ DndSuppressingNotificationsView dndView = (DndSuppressingNotificationsView) view;
+ boolean visible = this.clipTopAmount <= mText.getPaddingTop() * 0.6f;
+ dndView.performVisibilityAnimation(visible && !dndView.willBeGone());
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 42c774e..3efeb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -76,6 +76,7 @@
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.NotificationCounters;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
@@ -1252,6 +1253,8 @@
Dependency.get(NotificationBlockingHelperManager.class);
boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
+ Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+
// Continue with dismiss since we don't want the blocking helper to be directly associated
// with a certain notification.
performDismiss(fromAccessibility);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index bc572a2..0cc6137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -30,6 +30,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -270,7 +271,8 @@
/** Animates out the guts view via either a fade or a circular reveal. */
- private void animateClose(int x, int y, boolean shouldDoCircularReveal) {
+ @VisibleForTesting
+ void animateClose(int x, int y, boolean shouldDoCircularReveal) {
if (shouldDoCircularReveal) {
// Circular reveal originating at (x, y)
if (x == -1 || y == -1) {
@@ -340,7 +342,8 @@
}
}
- private void setExposed(boolean exposed, boolean needsFalsingProtection) {
+ @VisibleForTesting
+ void setExposed(boolean exposed, boolean needsFalsingProtection) {
final boolean wasExposed = mExposed;
mExposed = exposed;
mNeedsFalsingProtection = needsFalsingProtection;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 6a1740c..ec49f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -54,17 +54,20 @@
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationCounters;
import java.util.List;
/**
- * The guts of a notification revealed when performing a long press.
+ * The guts of a notification revealed when performing a long press. This also houses the blocking
+ * helper affordance that allows a user to keep/stop notifications after swiping one away.
*/
public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
private static final String TAG = "InfoGuts";
private INotificationManager mINotificationManager;
private PackageManager mPm;
+ private MetricsLogger mMetricsLogger;
private String mPackageName;
private String mAppName;
@@ -84,17 +87,27 @@
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
- /** Whether this view is being shown as part of the blocking helper */
+ /** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
private boolean mNegativeUserSentiment;
- private OnClickListener mOnKeepShowing = this::closeControls;
+ /** Counter tag that describes how the user exit or quit out of this view. */
+ private String mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+
+ private OnClickListener mOnKeepShowing = v -> {
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ closeControls(v);
+ };
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
swapContent(false);
};
private OnClickListener mOnUndo = v -> {
+ // Reset exit counter that we'll log and record an undo event separately (not an exit event)
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+ logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
swapContent(true);
};
@@ -151,6 +164,7 @@
boolean isUserSentimentNegative)
throws RemoteException {
mINotificationManager = iNotificationManager;
+ mMetricsLogger = Dependency.get(MetricsLogger.class);
mPackageName = pkg;
mNumUniqueChannelsInRow = numUniqueChannelsInRow;
mSbn = sbn;
@@ -183,6 +197,8 @@
bindHeader();
bindPrompt();
bindButtons();
+
+ logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_SHOWN);
}
private void bindHeader() throws RemoteException {
@@ -235,6 +251,8 @@
final int appUidF = mAppUid;
settingsButton.setOnClickListener(
(View view) -> {
+ logBlockingHelperCounter(
+ NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
mOnSettingsClickListener.onClick(view,
mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
@@ -269,6 +287,13 @@
}
}
+ @VisibleForTesting
+ void logBlockingHelperCounter(String counterTag) {
+ if (mIsForBlockingHelper) {
+ mMetricsLogger.count(counterTag, 1);
+ }
+ }
+
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
}
@@ -437,25 +462,15 @@
*/
@VisibleForTesting
void closeControls(View v) {
- if (mIsForBlockingHelper) {
- NotificationBlockingHelperManager manager =
- Dependency.get(NotificationBlockingHelperManager.class);
- manager.dismissCurrentBlockingHelper();
-
- // Since this won't get a callback via gutsContainer.closeControls, save the new
- // importance values immediately.
- saveImportance();
- } else {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
- }
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ mGutsContainer.getLocationOnScreen(parentLoc);
+ v.getLocationOnScreen(targetLoc);
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+ mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
}
@Override
@@ -480,6 +495,7 @@
if (save) {
saveImportance();
}
+ logBlockingHelperCounter(mExitReasonCounter);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java
new file mode 100644
index 0000000..9a12e8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.android.systemui.statusbar.notification;
+
+/**
+ * Constants for counter tags for Notification-related actions/views.
+ */
+public class NotificationCounters {
+ /** Counter tag for notification dismissal. */
+ public static final String NOTIFICATION_DISMISSED = "notification_dismissed";
+
+ /** Counter tag for when the blocking helper is shown to the user. */
+ public static final String BLOCKING_HELPER_SHOWN = "blocking_helper_shown";
+ /** Counter tag for when the blocking helper is dismissed via a miscellaneous interaction. */
+ public static final String BLOCKING_HELPER_DISMISSED = "blocking_helper_dismissed";
+ /** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
+ public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
+ "blocking_helper_stop_notifications";
+ /** Counter tag for when the user hits 'keep showing' in the blocking helper. */
+ public static final String BLOCKING_HELPER_KEEP_SHOWING =
+ "blocking_helper_keep_showing";
+ /**
+ * Counter tag for when the user hits undo in context of the blocking helper - this can happen
+ * multiple times per view.
+ */
+ public static final String BLOCKING_HELPER_UNDO = "blocking_helper_undo";
+ /** Counter tag for when the user hits the notification settings icon in the blocking helper. */
+ public static final String BLOCKING_HELPER_NOTIF_SETTINGS =
+ "blocking_helper_notif_settings";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 264f574..4b66ee5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -55,6 +55,7 @@
private final UnlockMethodCache mUnlockMethodCache;
private AccessibilityController mAccessibilityController;
private boolean mHasFingerPrintIcon;
+ private boolean mHasFaceUnlockIcon;
private int mDensity;
private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
@@ -130,6 +131,7 @@
}
int state = getState();
boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+ mHasFaceUnlockIcon = state == STATE_FACE_UNLOCK;
boolean useAdditionalPadding = anyFingerprintIcon;
boolean trustHidden = anyFingerprintIcon;
if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
@@ -179,6 +181,11 @@
setRestingAlpha(
anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
setImageDrawable(icon, false);
+ if (mHasFaceUnlockIcon) {
+ announceForAccessibility(getContext().getString(
+ R.string.accessibility_scanning_face));
+ }
+
mHasFingerPrintIcon = anyFingerprintIcon;
if (animation != null && isAnim) {
animation.forceAnimationOnUI();
@@ -228,6 +235,11 @@
info.addAction(unlock);
info.setHintText(getContext().getString(
R.string.accessibility_waiting_for_fingerprint));
+ } else if (mHasFaceUnlockIcon){
+ //Avoid 'button' to be spoken for scanning face
+ info.setClassName(LockIcon.class.getName());
+ info.setContentDescription(getContext().getString(
+ R.string.accessibility_scanning_face));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b650944..8bb73da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -199,6 +199,7 @@
private ValueAnimator mQsSizeChangeAnimator;
private boolean mShowEmptyShadeView;
+ private boolean mShowDndView;
private boolean mQsScrimEnabled = true;
private boolean mLastAnnouncementWasQuickSettings;
@@ -1599,8 +1600,8 @@
// When only empty shade view is visible in QS collapsed state, simulate that we would have
// it in expanded QS state as well so we don't run into troubles when fading the view in/out
// and expanding/collapsing the whole panel from/to quick settings.
- if (mNotificationStackScroller.getNotGoneChildCount() == 0
- && mShowEmptyShadeView) {
+ if ((mNotificationStackScroller.getNotGoneChildCount() == 0
+ && mShowEmptyShadeView) || mShowDndView) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -2243,13 +2244,17 @@
return mDozing;
}
+ public void showDndView(boolean dndViewVisible) {
+ mShowDndView = dndViewVisible;
+ mNotificationStackScroller.updateDndView(mShowDndView && !mQsExpanded);
+ }
+
public void showEmptyShadeView(boolean emptyShadeViewVisible) {
mShowEmptyShadeView = emptyShadeViewVisible;
updateEmptyShadeView();
}
private void updateEmptyShadeView() {
-
// Hide "No notifications" in QS.
mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ff0adb6..57a3556 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,6 +20,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -168,6 +169,7 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.qs.QSFragment;
@@ -188,6 +190,7 @@
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -413,7 +416,7 @@
protected NotificationViewHierarchyManager mViewHierarchyManager;
protected AppOpsListener mAppOpsListener;
protected KeyguardViewMediator mKeyguardViewMediator;
- private ZenModeController mZenController;
+ protected ZenModeController mZenController;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -878,6 +881,7 @@
mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
inflateEmptyShadeView();
+ inflateDndView();
inflateFooterView();
mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
@@ -1145,6 +1149,7 @@
protected void reevaluateStyles() {
inflateFooterView();
updateFooter();
+ inflateDndView();
inflateEmptyShadeView();
updateEmptyShadeView();
}
@@ -1166,6 +1171,19 @@
mStackScroller.setEmptyShadeView(mEmptyShadeView);
}
+ private void inflateDndView() {
+ if (mStackScroller == null) {
+ return;
+ }
+ mDndView = (DndSuppressingNotificationsView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_dnd_suppressing_notifications, mStackScroller, false);
+ mDndView.setOnContentClickListener(v -> {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ });
+ mStackScroller.setDndView(mDndView);
+ }
+
private void inflateFooterView() {
if (mStackScroller == null) {
return;
@@ -1460,9 +1478,11 @@
@VisibleForTesting
protected void updateFooter() {
boolean showFooterView = mState != StatusBarState.KEYGUARD
+ && !areNotificationsHidden()
&& mEntryManager.getNotificationData().getActiveNotifications().size() != 0
&& !mRemoteInputManager.getController().isRemoteInputActive();
boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
+ && !areNotificationsHidden()
&& hasActiveClearableNotifications();
mStackScroller.updateFooterView(showFooterView, showDismissView);
@@ -1485,10 +1505,13 @@
return false;
}
- private void updateEmptyShadeView() {
- boolean showEmptyShadeView =
- mState != StatusBarState.KEYGUARD &&
- mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ @VisibleForTesting
+ protected void updateEmptyShadeView() {
+ boolean showDndView = mState != StatusBarState.KEYGUARD && areNotificationsHidden();
+ boolean showEmptyShadeView = !showDndView
+ && mState != StatusBarState.KEYGUARD
+ && mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ mNotificationPanel.showDndView(showDndView);
mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
}
@@ -4988,6 +5011,7 @@
protected NotificationShelf mNotificationShelf;
protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
+ protected DndSuppressingNotificationsView mDndView;
protected AssistManager mAssistManager;
@@ -5472,6 +5496,11 @@
mStackScroller.getChildCount() - offsetFromEnd++);
}
+ if (mDndView != null) {
+ mStackScroller.changeViewPosition(mDndView,
+ mStackScroller.getChildCount() - offsetFromEnd++);
+ }
+
mStackScroller.changeViewPosition(mEmptyShadeView,
mStackScroller.getChildCount() - offsetFromEnd++);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5275e27..eeaa6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -81,6 +81,7 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
@@ -236,6 +237,7 @@
protected boolean mScrollingEnabled;
protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
+ protected DndSuppressingNotificationsView mDndView;
private boolean mDismissAllInProgress;
private boolean mFadeNotificationsOnDismiss;
@@ -1006,7 +1008,8 @@
private float getAppearEndPosition() {
int appearPosition;
int notGoneChildCount = getNotGoneChildCount();
- if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
+ if ((mEmptyShadeView.getVisibility() == GONE && mDndView.getVisibility() == GONE)
+ && notGoneChildCount != 0) {
if (isHeadsUpTransition()
|| (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
appearPosition = getTopHeadsUpPinnedHeight();
@@ -1016,6 +1019,8 @@
appearPosition += mShelf.getIntrinsicHeight();
}
}
+ } else if (mEmptyShadeView.getVisibility() == GONE) {
+ appearPosition = mDndView.getHeight();
} else {
appearPosition = mEmptyShadeView.getHeight();
}
@@ -2608,19 +2613,6 @@
return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
}
- public int getFirstChildIntrinsicHeight() {
- final ExpandableView firstChild = getFirstChildNotGone();
- int firstChildMinHeight = firstChild != null
- ? firstChild.getIntrinsicHeight()
- : mEmptyShadeView != null
- ? mEmptyShadeView.getIntrinsicHeight()
- : mCollapsedSize;
- if (mOwnScrollY > 0) {
- firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
- }
- return firstChildMinHeight;
- }
-
public float getTopPaddingOverflow() {
return mTopPaddingOverflow;
}
@@ -3918,6 +3910,7 @@
final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor);
mFooterView.setTextColor(textColor);
mEmptyShadeView.setTextColor(textColor);
+ mDndView.setColor(textColor);
}
public void goToFullShade(long delay) {
@@ -3925,6 +3918,7 @@
mFooterView.setInvisible();
}
mEmptyShadeView.setInvisible();
+ mDndView.setInvisible();
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
mNeedsAnimation = true;
@@ -4076,25 +4070,39 @@
int newVisibility = visible ? VISIBLE : GONE;
boolean changedVisibility = oldVisibility != newVisibility;
- if (changedVisibility || newVisibility != GONE) {
+ if (changedVisibility) {
if (newVisibility != GONE) {
- int oldText = mEmptyShadeView.getTextResource();
- int newText;
- if (mStatusBar.areNotificationsHidden()) {
- newText = R.string.dnd_suppressing_shade_text;
- } else {
- newText = R.string.empty_shade_text;
- }
- if (changedVisibility || !Objects.equals(oldText, newText)) {
- mEmptyShadeView.setText(newText);
- showFooterView(mEmptyShadeView);
- }
+ showFooterView(mEmptyShadeView);
} else {
hideFooterView(mEmptyShadeView, true);
}
}
}
+ public void setDndView(DndSuppressingNotificationsView dndView) {
+ int index = -1;
+ if (mDndView != null) {
+ index = indexOfChild(mDndView);
+ removeView(mDndView);
+ }
+ mDndView = dndView;
+ addView(mDndView, index);
+ }
+
+ public void updateDndView(boolean visible) {
+ int oldVisibility = mDndView.willBeGone() ? GONE : mDndView.getVisibility();
+ int newVisibility = visible ? VISIBLE : GONE;
+
+ boolean changedVisibility = oldVisibility != newVisibility;
+ if (changedVisibility) {
+ if (newVisibility != GONE) {
+ showFooterView(mDndView);
+ } else {
+ hideFooterView(mDndView, true);
+ }
+ }
+ }
+
public void updateFooterView(boolean visible, boolean showDismissView) {
if (mFooterView == null) {
return;
@@ -4119,10 +4127,16 @@
} else {
footerView.setInvisible();
}
- footerView.setVisibility(VISIBLE);
- footerView.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(footerView);
+ Runnable onShowFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ footerView.setVisibility(VISIBLE);
+ footerView.setWillBeGone(false);
+ updateContentHeight();
+ notifyHeightChangeListener(footerView);
+ }
+ };
+ footerView.performVisibilityAnimation(true, onShowFinishRunnable);
}
private void hideFooterView(StackScrollerDecorView footerView, boolean isButtonVisible) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index b0530c8..65fd7f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -33,9 +33,12 @@
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,7 +47,6 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -52,7 +54,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
-import android.os.Looper;
+import android.os.IBinder;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -65,6 +67,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -100,7 +103,7 @@
private StatusBarNotification mSbn;
@Rule public MockitoRule mockito = MockitoJUnit.rule();
- private Looper mLooper;
+ @Mock private MetricsLogger mMetricsLogger;
@Mock private INotificationManager mMockINotificationManager;
@Mock private PackageManager mMockPackageManager;
@Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@@ -112,6 +115,7 @@
mBlockingHelperManager);
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
// Inflate the layout
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
@@ -301,6 +305,24 @@
}
@Test
+ public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
+ mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+ verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
+ }
+
+ @Test
+ public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
+ // Bind notification logs an event, so this counts as one invocation for the metrics logger.
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
+ true);
+ mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+ verify(mMetricsLogger, times(2)).count(anyString(), anyInt());
+ }
+
+ @Test
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -471,6 +493,13 @@
false /* isNonblockable */, true /* isForBlockingHelper */,
true /* isUserSentimentNegative */);
+ NotificationGuts guts = spy(new NotificationGuts(mContext, null));
+ when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
+ doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
+ doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
+ guts.setGutsContent(mNotificationInfo);
+ mNotificationInfo.setGutsParent(guts);
+
mNotificationInfo.findViewById(R.id.keep).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
@@ -495,6 +524,9 @@
false /* isNonblockable */,
true /* isForBlockingHelper */,
false /* isUserSentimentNegative */);
+ NotificationGuts guts = mock(NotificationGuts.class);
+ doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+ mNotificationInfo.setGutsParent(guts);
mNotificationInfo.closeControls(mNotificationInfo);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 37e0005..41cf869 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -78,6 +78,7 @@
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.FooterView;
import com.android.systemui.statusbar.FooterViewButton;
@@ -103,6 +104,7 @@
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import org.junit.Before;
@@ -132,6 +134,7 @@
@Mock private ScrimController mScrimController;
@Mock private ArrayList<Entry> mNotificationList;
@Mock private FingerprintUnlockController mFingerprintUnlockController;
+ @Mock private ZenModeController mZenController;
@Mock private NotificationData mNotificationData;
// Mock dependencies:
@@ -163,6 +166,7 @@
mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class));
+ mDependency.injectTestDependency(ZenModeController.class, mZenController);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -213,7 +217,7 @@
mRemoteInputManager, mock(NotificationGroupManager.class),
mock(FalsingManager.class), mock(StatusBarWindowManager.class),
mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
- mock(NotificationShelf.class), mLockscreenUserManager,
+ mock(NotificationShelf.class), mLockscreenUserManager, mZenController,
mock(CommandQueue.class));
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
@@ -676,6 +680,60 @@
}
@Test
+ public void testDNDView_atEnd() {
+ // add footer
+ mStatusBar.reevaluateStyles();
+
+ // add notification
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ mStackScroller.addContainerView(row);
+
+ mStatusBar.onUpdateRowStates();
+
+ // move dnd view to end
+ verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+ verify(mStackScroller).changeViewPosition(any(DndSuppressingNotificationsView.class),
+ eq(-2 /* end */));
+ }
+
+ @Test
+ public void updateEmptyShade_nonNotificationsDndOff() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+ assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(false);
+ verify(mNotificationPanelView).showEmptyShadeView(true);
+ }
+
+ @Test
+ public void updateEmptyShade_noNotificationsDndOn() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+ assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+ when(mZenController.areNotificationsHiddenInShade()).thenReturn(true);
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(true);
+ verify(mNotificationPanelView).showEmptyShadeView(false);
+ }
+
+ @Test
+ public void updateEmptyShade_yesNotificationsDndOff() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ ArrayList<Entry> entries = new ArrayList<>();
+ entries.add(mock(Entry.class));
+ when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+ assertEquals(1, mEntryManager.getNotificationData().getActiveNotifications().size());
+ when(mZenController.areNotificationsHiddenInShade()).thenReturn(false);
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(false);
+ verify(mNotificationPanelView).showEmptyShadeView(false);
+ }
+
+ @Test
public void testSetState_changesIsFullScreenUserSwitcherState() {
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
assertFalse(mStatusBar.isFullScreenUserSwitcherState());
@@ -721,6 +779,7 @@
DozeScrimController dozeScrimController,
NotificationShelf notificationShelf,
NotificationLockscreenUserManager notificationLockscreenUserManager,
+ ZenModeController zenController,
CommandQueue commandQueue) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
@@ -749,6 +808,7 @@
mDozeScrimController = dozeScrimController;
mNotificationShelf = notificationShelf;
mLockscreenUserManager = notificationLockscreenUserManager;
+ mZenController = zenController;
mCommandQueue = commandQueue;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index eeb4209..3d17ec4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -34,6 +35,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.TestableDependency;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FooterView;
import com.android.systemui.statusbar.NotificationBlockingHelperManager;
@@ -69,6 +71,7 @@
@Mock private NotificationGroupManager mGroupManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
+ @Mock private DndSuppressingNotificationsView mDndView;
@Before
@UiThreadTest
@@ -86,6 +89,7 @@
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ mStackScroller.setDndView(mDndView);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
@@ -120,40 +124,6 @@
}
@Test
- public void updateEmptyView_dndSuppressing() {
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(true);
-
- mStackScroller.updateEmptyShadeView(true);
-
- verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
- }
-
- @Test
- public void updateEmptyView_dndNotSuppressing() {
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(false);
-
- mStackScroller.updateEmptyShadeView(true);
-
- verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- }
-
- @Test
- public void updateEmptyView_noNotificationsToDndSuppressing() {
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
- verify(mEmptyShadeView).setText(R.string.empty_shade_text);
-
- when(mBar.areNotificationsHidden()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
- verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
- }
-
- @Test
@UiThreadTest
public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
mStackScroller.setExpandedHeight(0f);
@@ -173,7 +143,7 @@
mStackScroller.updateFooterView(true, false);
- verify(view).setVisibility(View.VISIBLE);
+ verify(view).performVisibilityAnimation(eq(true), any());
verify(view).performSecondaryVisibilityAnimation(false);
}
@@ -186,7 +156,7 @@
mStackScroller.updateFooterView(true, true);
- verify(view).setVisibility(View.VISIBLE);
+ verify(view).performVisibilityAnimation(eq(true), any());
verify(view).performSecondaryVisibilityAnimation(true);
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e33ef1f..7dd85ba 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5717,6 +5717,29 @@
// OS: P
SETTINGS_ZEN_NOTIFICATIONS = 1400;
+ // An event category for slices.
+ // OPEN: Slice became visible.
+ // CLOSE: Slice became invisible.
+ // ACTION: Slice was tapped.
+ SLICE = 1401;
+
+ // The authority part of the slice URI
+ FIELD_SLICE_AUTHORITY = 1402;
+
+ // The path part of the slice URI
+ FIELD_SLICE_PATH = 1403;
+
+ // The authority part of the subslice URI
+ FIELD_SUBSLICE_AUTHORITY = 1404;
+
+ // The path part of the subslice URI
+ FIELD_SUBSLICE_PATH = 1405;
+
+ // OPEN: DND onboarding activity > don't update button
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 821cca1..44edabc 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -421,7 +421,7 @@
// after the app's agent runs to handle its private filesystem
// contents, back up any OBB content it has on its behalf.
- if (mIncludeObbs) {
+ if (mIncludeObbs && !isSharedStorage) {
boolean obbOkay = obbConnection.backupObbs(pkg, out);
if (!obbOkay) {
throw new RuntimeException("Failure writing OBB stack for " + pkg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 193d3f4..a8e63f6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5049,9 +5049,20 @@
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
+ resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
+ true /*validateIncomingUser*/);
+ }
+
+ public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
+ boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+
+ userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
+ Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
+
// TODO: Switch to user app stacks here.
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
@@ -26344,6 +26355,16 @@
}
@Override
+ public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
+ Intent intent, Bundle options, int userId) {
+ return ActivityManagerService.this.startActivityAsUser(
+ caller, callerPacakge, intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId,
+ false /*validateIncomingUser*/);
+ }
+
+ @Override
public int getUidProcessState(int uid) {
return getUidState(uid);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 548290e..4ace689 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1315,10 +1315,6 @@
return aInfo;
}
- ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
- return resolveIntent(intent, resolvedType, userId, 0, Binder.getCallingUid());
- }
-
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,
int filterCallingUid) {
synchronized (mService) {
@@ -1330,9 +1326,19 @@
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
modifiedFlags |= PackageManager.MATCH_INSTANT;
}
- return mService.getPackageManagerInternalLocked().resolveIntent(
- intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
+ // In order to allow cross-profile lookup, we clear the calling identity here.
+ // Note the binder identity won't affect the result, but filterCallingUid will.
+
+ // Cross-user/profile call check are done at the entry points
+ // (e.g. AMS.startActivityAsUser).
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mService.getPackageManagerInternalLocked().resolveIntent(
+ intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
} finally {
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 31ccf35..5e29d10 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -233,7 +233,7 @@
* ensures {@code targetUserId} is a real user ID and not a special user ID such as
* {@link android.os.UserHandle#USER_ALL}, etc.
*/
- private int checkTargetUser(int targetUserId, boolean validateIncomingUser,
+ int checkTargetUser(int targetUserId, boolean validateIncomingUser,
int realCallingPid, int realCallingUid, String reason) {
if (validateIncomingUser) {
return mService.mUserController.handleIncomingUser(realCallingPid, realCallingUid,
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 5b6b508..8c3ff34 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -203,7 +203,7 @@
mResolvedType = null;
final UserInfo parent = mUserManager.getProfileParent(mUserId);
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -223,9 +223,11 @@
final UserInfo parent = mUserManager.getProfileParent(mUserId);
if (parent != null) {
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
+ mRealCallingUid);
} else {
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
+ mRealCallingUid);
}
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
@@ -244,7 +246,8 @@
final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
.setPackage(suspendingPackage);
final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
- final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
+ final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId,
+ 0, mRealCallingUid);
if (resolvedInfo != null && resolvedInfo.activityInfo != null
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
@@ -276,7 +279,7 @@
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -309,7 +312,7 @@
}
final UserInfo parent = mUserManager.getProfileParent(mUserId);
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -362,7 +365,7 @@
mCallingUid = mRealCallingUid;
mResolvedType = null;
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7ff7d9a..fb4107c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -791,7 +791,7 @@
callingUid = realCallingUid;
callingPid = realCallingPid;
- rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0, realCallingUid);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
@@ -952,6 +952,9 @@
mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
boolean componentSpecified = intent.getComponent() != null;
+ final int realCallingPid = Binder.getCallingPid();
+ final int realCallingUid = Binder.getCallingUid();
+
// Save a copy in case ephemeral needs it
final Intent ephemeralIntent = new Intent(intent);
// Don't modify the client's object!
@@ -969,7 +972,8 @@
componentSpecified = false;
}
- ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+ 0 /* matchFlags */, realCallingUid);
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
@@ -991,7 +995,7 @@
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- Binder.getCallingUid());
+ realCallingUid);
}
}
}
@@ -999,8 +1003,6 @@
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
synchronized (mService) {
- final int realCallingPid = Binder.getCallingPid();
- final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
callingPid = -1;
@@ -1073,7 +1075,8 @@
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
componentSpecified = true;
- rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
+ rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
+ 0 /* matchFlags */, realCallingUid);
aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ec3949f..b68ef11 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
@@ -710,7 +711,7 @@
StatusBarNotification sbn = r.sbn;
cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
sbn.getId(), Notification.FLAG_AUTO_CANCEL,
- Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+ FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
REASON_CLICK, nv.rank, nv.count, null);
nv.recycle();
reportUserInteraction(r);
@@ -754,7 +755,7 @@
}
}
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
true, userId, REASON_CANCEL, nv.rank, nv.count,null);
nv.recycle();
}
@@ -985,7 +986,7 @@
cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
record.sbn.getPackageName(), record.sbn.getTag(),
record.sbn.getId(), 0,
- Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
+ FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
REASON_TIMEOUT, null);
}
}
@@ -2084,7 +2085,7 @@
// Don't allow client applications to cancel foreground service notis or autobundled
// summaries.
final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
- (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
+ (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
}
@@ -2099,7 +2100,7 @@
// Calling from user space, don't allow the canceling of actively
// running foreground services.
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
- pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
+ pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
REASON_APP_CANCEL_ALL, null);
}
@@ -2685,7 +2686,7 @@
private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
true,
userId, REASON_LISTENER_CANCEL, info);
}
@@ -3876,7 +3877,9 @@
for (int j = 0; j < listenerSize; j++) {
if (i > 0) pw.print(',');
final ManagedServiceInfo listener = listeners.valueAt(i);
- pw.print(listener.component);
+ if (listener != null) {
+ pw.print(listener.component);
+ }
}
}
pw.println(')');
@@ -3962,7 +3965,7 @@
// FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
// initially *and* force remove FLAG_FOREGROUND_SERVICE.
sbn.getNotification().flags =
- (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
+ (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
mRankingHelper.sort(mNotificationList);
mListeners.notifyPostedLocked(r, r);
}
@@ -4048,7 +4051,7 @@
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
- if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
+ if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0
&& (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
&& (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
// Increase the importance of foreground service notifications unless the user had an
@@ -4429,7 +4432,7 @@
mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
notification.flags |=
- old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+ old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
r.setInterruptive(isVisuallyInterruptive(old, r));
}
@@ -4438,7 +4441,7 @@
// Ensure if this is a foreground service that the proper additional
// flags are set.
- if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
notification.flags |= Notification.FLAG_ONGOING_EVENT
| Notification.FLAG_NO_CLEAR;
}
@@ -4506,6 +4509,13 @@
if (oldN.extras == null || newN.extras == null) {
return false;
}
+
+ // Ignore visual interruptions from foreground services because users
+ // consider them one 'session'. Count them for everything else.
+ if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
+ return false;
+ }
+
if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
newN.extras.get(Notification.EXTRA_TITLE))) {
return true;
@@ -5805,7 +5815,7 @@
final StatusBarNotification childSbn = childR.sbn;
if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
childR.getGroupKey().equals(parentNotification.getGroupKey())
- && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
+ && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
&& (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
childSbn.getTag(), userId, 0, 0, reason, listenerName);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 156f702..658c7f1 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -173,18 +173,6 @@
}
}
- public boolean shouldSuppressWhenScreenOff() {
- synchronized (mConfig) {
- return !mConfig.allowWhenScreenOff;
- }
- }
-
- public boolean shouldSuppressWhenScreenOn() {
- synchronized (mConfig) {
- return !mConfig.allowWhenScreenOn;
- }
- }
-
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -592,14 +580,12 @@
return;
}
pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
- + "messages=%b,messagesFrom=%s,"
- + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
+ + "messages=%b,messagesFrom=%s,events=%b,reminders=%b)\n",
config.allowAlarms, config.allowMedia, config.allowSystem,
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
config.allowRepeatCallers, config.allowMessages,
ZenModeConfig.sourceToString(config.allowMessagesFrom),
- config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
- config.allowWhenScreenOn);
+ config.allowEvents, config.allowReminders);
pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
@@ -1185,7 +1171,7 @@
private void showZenUpgradeNotification(int zen) {
final boolean showNotification = mIsBootComplete
- && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && zen != Global.ZEN_MODE_OFF
&& Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
@@ -1204,17 +1190,20 @@
mContext.getResources().getString(R.string.global_action_settings));
int title = R.string.zen_upgrade_notification_title;
int content = R.string.zen_upgrade_notification_content;
+ int drawable = R.drawable.ic_zen_24dp;
if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
getNotificationPolicy().suppressedVisualEffects)) {
title = R.string.zen_upgrade_notification_visd_title;
content = R.string.zen_upgrade_notification_visd_content;
+ drawable = R.drawable.ic_dnd_block_notifications;
}
+
Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_settings_24dp)
- .setLargeIcon(Icon.createWithResource(mContext, R.drawable.ic_zen_24dp))
+ .setLargeIcon(Icon.createWithResource(mContext, drawable))
.setContentTitle(mContext.getResources().getString(title))
.setContentText(mContext.getResources().getString(content))
.setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 595de9e..feac8e6 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,6 +21,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
+import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -560,7 +561,7 @@
}
@Override
- public void startActivityAsUser(String callingPackage,
+ public void startActivityAsUser(IApplicationThread caller, String callingPackage,
ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
@@ -574,6 +575,8 @@
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
launchIntent.setPackage(component.getPackageName());
+ boolean canLaunch = false;
+
final int callingUid = injectBinderCallingUid();
long ident = Binder.clearCallingIdentity();
try {
@@ -604,35 +607,42 @@
// this component so ok to launch.
launchIntent.setPackage(null);
launchIntent.setComponent(component);
- mContext.startActivityAsUser(launchIntent, opts, user);
- return;
+ canLaunch = true;
+ break;
}
}
- throw new SecurityException("Attempt to launch activity without "
- + " category Intent.CATEGORY_LAUNCHER " + component);
+ if (!canLaunch) {
+ throw new SecurityException("Attempt to launch activity without "
+ + " category Intent.CATEGORY_LAUNCHER " + component);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
+ mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+ launchIntent, opts, user.getIdentifier());
}
@Override
- public void showAppDetailsAsUser(String callingPackage, ComponentName component,
+ public void showAppDetailsAsUser(IApplicationThread caller,
+ String callingPackage, ComponentName component,
Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
return;
}
+ final Intent intent;
long ident = Binder.clearCallingIdentity();
try {
String packageName = component.getPackageName();
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setSourceBounds(sourceBounds);
- mContext.startActivityAsUser(intent, opts, user);
} finally {
Binder.restoreCallingIdentity(ident);
}
+ mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+ intent, opts, user.getIdentifier());
}
/** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 144f289..681b0c9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -22462,9 +22462,13 @@
}
final String volumeUuid = pkg.volumeUuid;
final String packageName = pkg.packageName;
- final ApplicationInfo app = (ps == null)
+
+ ApplicationInfo app = (ps == null)
? pkg.applicationInfo
: PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
+ if (app == null) {
+ app = pkg.applicationInfo;
+ }
final int appId = UserHandle.getAppId(app.uid);
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 eb1c997..58f5898 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -528,7 +529,7 @@
PKG, new ParceledListSlice(Arrays.asList(channel)));
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
@@ -557,7 +558,7 @@
mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
@@ -601,7 +602,7 @@
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
@@ -759,7 +760,7 @@
@Test
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
@@ -773,7 +774,7 @@
@Test
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
@@ -901,7 +902,7 @@
@Test
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
@@ -909,14 +910,14 @@
waitForIdle();
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
- assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
+ assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
}
@Test
public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags =
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
@@ -937,7 +938,7 @@
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -960,7 +961,7 @@
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -984,7 +985,7 @@
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -2187,7 +2188,6 @@
@Test
public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
final String upgradeXml = "<notification-policy version=\"1\">"
- + "<zen></zen>"
+ "<ranking></ranking>"
+ "<enabled_listeners>"
+ "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
@@ -2215,7 +2215,6 @@
@Test
public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
final String preupgradeXml = "<notification-policy version=\"1\">"
- + "<zen></zen>"
+ "<ranking></ranking>"
+ "</notification-policy>";
mService.readPolicyXml(
@@ -2257,7 +2256,7 @@
NotificationChannel.DEFAULT_CHANNEL_ID)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2272,7 +2271,7 @@
nb = new Notification.Builder(mContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2670,6 +2669,26 @@
}
@Test
+ public void testVisualDifference_foreground() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setContentTitle("foo");
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .setContentTitle("bar");
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertFalse(mService.isVisuallyInterruptive(r1, r2));
+ }
+
+ @Test
public void testVisualDifference_diffTitle() {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentTitle("foo");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index d846d21..36ec221 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -336,6 +336,90 @@
}
@Test
+ public void testRemoteViews_layoutChange() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(189);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_layoutSame() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_sequenceChange() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ when(a.getSequenceNumber()).thenReturn(1);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+ when(b.getSequenceNumber()).thenReturn(2);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_sequenceSame() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ when(a.getSequenceNumber()).thenReturn(1);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+ when(b.getSequenceNumber()).thenReturn(1);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
public void testActionsDifferent_null() {
Notification n1 = new Notification.Builder(mContext, "test")
.build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index d02a983..afc1263 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,6 +17,9 @@
package com.android.server.notification;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertEquals;
@@ -569,8 +572,6 @@
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
@@ -593,8 +594,6 @@
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -645,6 +644,115 @@
}
@Test
+ public void testMigrateSuppressedVisualEffects_oneExistsButOff() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
+ public void testMigrateSuppressedVisualEffects_bothExistButOff() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
+ public void testMigrateSuppressedVisualEffects_bothExistButOn() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"true\" visualScreenOn=\"true\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
+ | SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_PEEK,
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" visualScreenOn=\"true\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"true\" visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS,
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
public void testReadXmlResetDefaultRules() throws Exception {
setupZenConfig();
@@ -705,16 +813,6 @@
setupZenConfigMaintained();
}
- @Test
- public void testPolicyReadsSuppressedEffects() {
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
- mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
-
- NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
- assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
- }
-
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
@@ -725,8 +823,6 @@
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -746,8 +842,6 @@
assertTrue(mZenModeHelperSpy.mConfig.allowMessages);
assertTrue(mZenModeHelperSpy.mConfig.allowEvents);
assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
- assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOff);
- assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOn);
assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
}
}