Merge "haptics: remove unused haptics_customization_enabled" into main
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fa9346e..4bf8879 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -607,9 +607,9 @@
Configuration createdConfig;
Configuration overrideConfig;
@NonNull
- private ActivityWindowInfo mActivityWindowInfo;
- @Nullable
- private ActivityWindowInfo mLastReportedActivityWindowInfo;
+ private final ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo();
+ @NonNull
+ private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo();
// Used for consolidating configs before sending on to Activity.
private final Configuration tmpConfig = new Configuration();
@@ -700,7 +700,7 @@
mSceneTransitionInfo = sceneTransitionInfo;
mLaunchedFromBubble = launchedFromBubble;
mTaskFragmentToken = taskFragmentToken;
- mActivityWindowInfo = activityWindowInfo;
+ mActivityWindowInfo.set(activityWindowInfo);
init();
}
@@ -720,7 +720,7 @@
throw new IllegalStateException(
"Received config update for non-existing activity");
}
- if (activityWindowInfoFlag() && activityWindowInfo == null) {
+ if (activityWindowInfo == null) {
Log.w(TAG, "Received empty ActivityWindowInfo update for r=" + activity);
activityWindowInfo = mActivityWindowInfo;
}
@@ -6063,7 +6063,7 @@
target.createdConfig = config.getGlobalConfiguration();
target.overrideConfig = config.getOverrideConfiguration();
target.pendingConfigChanges |= configChanges;
- target.mActivityWindowInfo = activityWindowInfo;
+ target.mActivityWindowInfo.set(activityWindowInfo);
}
return scheduleRelaunch ? target : null;
@@ -6257,7 +6257,7 @@
}
r.startsNotResumed = startsNotResumed;
r.overrideConfig = overrideConfig;
- r.mActivityWindowInfo = activityWindowInfo;
+ r.mActivityWindowInfo.set(activityWindowInfo);
handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
}
@@ -6759,7 +6759,7 @@
// Perform updates.
r.overrideConfig = overrideConfig;
- r.mActivityWindowInfo = activityWindowInfo;
+ r.mActivityWindowInfo.set(activityWindowInfo);
final ViewRootImpl viewRoot = r.activity.mDecor != null
? r.activity.mDecor.getViewRootImpl() : null;
@@ -6792,11 +6792,10 @@
if (!activityWindowInfoFlag()) {
return;
}
- if (r.mActivityWindowInfo == null
- || r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
+ if (r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
return;
}
- r.mLastReportedActivityWindowInfo = r.mActivityWindowInfo;
+ r.mLastReportedActivityWindowInfo.set(r.mActivityWindowInfo);
ClientTransactionListenerController.getInstance().onActivityWindowInfoChanged(r.token,
r.mActivityWindowInfo);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7337a7c..d7b9a2c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -24,6 +24,7 @@
import static android.graphics.drawable.Icon.TYPE_URI;
import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
import static android.app.Flags.evenlyDividedCallStyleActionLayout;
+import static android.app.Flags.updateRankingTime;
import static java.util.Objects.requireNonNull;
@@ -339,8 +340,9 @@
/**
* The creation time of the notification
+ * @hide
*/
- private long creationTime;
+ public long creationTime;
/**
* The resource id of a drawable to use as the icon in the status bar.
@@ -2578,7 +2580,11 @@
public Notification()
{
this.when = System.currentTimeMillis();
- this.creationTime = System.currentTimeMillis();
+ if (updateRankingTime()) {
+ creationTime = when;
+ } else {
+ this.creationTime = System.currentTimeMillis();
+ }
this.priority = PRIORITY_DEFAULT;
}
@@ -2589,6 +2595,9 @@
public Notification(Context context, int icon, CharSequence tickerText, long when,
CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
{
+ if (updateRankingTime()) {
+ creationTime = when;
+ }
new Builder(context)
.setWhen(when)
.setSmallIcon(icon)
@@ -2618,7 +2627,11 @@
this.icon = icon;
this.tickerText = tickerText;
this.when = when;
- this.creationTime = System.currentTimeMillis();
+ if (updateRankingTime()) {
+ creationTime = when;
+ } else {
+ this.creationTime = System.currentTimeMillis();
+ }
}
/**
@@ -6843,7 +6856,9 @@
}
}
- mN.creationTime = System.currentTimeMillis();
+ if (!updateRankingTime()) {
+ mN.creationTime = System.currentTimeMillis();
+ }
// lazy stuff from mContext; see comment in Builder(Context, Notification)
Notification.addFieldsFromContext(mContext, mN);
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index e9a7460..29ffdc5 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -71,4 +71,14 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "update_ranking_time"
+ namespace: "systemui"
+ description: "Updates notification sorting criteria to highlight new content while maintaining stability"
+ bug: "326016985"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 7383d07..c55b0f1 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -122,7 +122,7 @@
}
for (Object activityWindowInfoChangedListener : activityWindowInfoChangedListeners) {
((BiConsumer<IBinder, ActivityWindowInfo>) activityWindowInfoChangedListener)
- .accept(activityToken, activityWindowInfo);
+ .accept(activityToken, new ActivityWindowInfo(activityWindowInfo));
}
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index b6066ba..9c63d0d 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -1297,6 +1297,17 @@
*/
@Nullable
private Drawable resolveAvatarImageForOneToOne(Icon conversationIcon) {
+ final Drawable conversationIconDrawable =
+ tryLoadingSizeRestrictedIconForOneToOne(conversationIcon);
+ if (conversationIconDrawable != null) {
+ return conversationIconDrawable;
+ }
+ // when size restricted icon loading fails, we fallback to icons load drawable.
+ return loadDrawableFromIcon(conversationIcon);
+ }
+
+ @Nullable
+ private Drawable tryLoadingSizeRestrictedIconForOneToOne(Icon conversationIcon) {
try {
return mConversationIconView.loadSizeRestrictedIcon(conversationIcon);
} catch (Exception ex) {
@@ -1309,6 +1320,11 @@
*/
@Nullable
private Drawable resolveAvatarImageForFacePile(Icon conversationIcon) {
+ return loadDrawableFromIcon(conversationIcon);
+ }
+
+ @Nullable
+ private Drawable loadDrawableFromIcon(Icon conversationIcon) {
try {
return conversationIcon.loadDrawable(getContext());
} catch (Exception ex) {
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 488f017..ff28055 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -1258,7 +1258,8 @@
@Test
public void testTriggerFromMainProfile_inSingleUserMode_withWorkProfilePresent() {
mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
- android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
+ android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE,
+ android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
markWorkProfileUserAvailable();
setTabOwnerUserHandleForLaunch(PERSONAL_USER_HANDLE);
Intent sendIntent = createSendImageIntent();
@@ -1281,7 +1282,8 @@
@Test
public void testTriggerFromWorkProfile_inSingleUserMode() {
mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
- android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
+ android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE,
+ android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
markWorkProfileUserAvailable();
setTabOwnerUserHandleForLaunch(sOverrides.workProfileUserHandle);
Intent sendIntent = createSendImageIntent();
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 014b841..341c3e8c 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -345,6 +345,7 @@
"jni/android_nio_utils.cpp",
"jni/android_util_PathParser.cpp",
+ "jni/AnimatedImageDrawable.cpp",
"jni/Bitmap.cpp",
"jni/BitmapRegionDecoder.cpp",
"jni/BufferUtils.cpp",
@@ -418,7 +419,6 @@
target: {
android: {
srcs: [ // sources that depend on android only libraries
- "jni/AnimatedImageDrawable.cpp",
"jni/android_graphics_TextureLayer.cpp",
"jni/android_graphics_HardwareRenderer.cpp",
"jni/android_graphics_HardwareBufferRenderer.cpp",
@@ -539,6 +539,7 @@
"renderthread/RenderTask.cpp",
"renderthread/TimeLord.cpp",
"hwui/AnimatedImageDrawable.cpp",
+ "hwui/AnimatedImageThread.cpp",
"hwui/Bitmap.cpp",
"hwui/BlurDrawLooper.cpp",
"hwui/Canvas.cpp",
@@ -599,7 +600,6 @@
local_include_dirs: ["platform/android"],
srcs: [
- "hwui/AnimatedImageThread.cpp",
"pipeline/skia/ATraceMemoryDump.cpp",
"pipeline/skia/GLFunctorDrawable.cpp",
"pipeline/skia/LayerDrawable.cpp",
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 27773a6..69613c7 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -15,18 +15,16 @@
*/
#include "AnimatedImageDrawable.h"
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
-#include "AnimatedImageThread.h"
-#endif
-
-#include <gui/TraceUtils.h>
-#include "pipeline/skia/SkiaUtils.h"
#include <SkPicture.h>
#include <SkRefCnt.h>
+#include <gui/TraceUtils.h>
#include <optional>
+#include "AnimatedImageThread.h"
+#include "pipeline/skia/SkiaUtils.h"
+
namespace android {
AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
@@ -185,10 +183,8 @@
} else if (starting) {
// The image has animated, and now is being reset. Queue up the first
// frame, but keep showing the current frame until the first is ready.
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
auto& thread = uirenderer::AnimatedImageThread::getInstance();
mNextSnapshot = thread.reset(sk_ref_sp(this));
-#endif
}
bool finalFrame = false;
@@ -214,10 +210,8 @@
}
if (mRunning && !mNextSnapshot.valid()) {
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
auto& thread = uirenderer::AnimatedImageThread::getInstance();
mNextSnapshot = thread.decodeNextFrame(sk_ref_sp(this));
-#endif
}
if (!drawDirectly) {
diff --git a/libs/hwui/hwui/AnimatedImageThread.cpp b/libs/hwui/hwui/AnimatedImageThread.cpp
index 825dd4c..e39c8d5 100644
--- a/libs/hwui/hwui/AnimatedImageThread.cpp
+++ b/libs/hwui/hwui/AnimatedImageThread.cpp
@@ -16,7 +16,9 @@
#include "AnimatedImageThread.h"
+#ifdef __ANDROID__
#include <sys/resource.h>
+#endif
namespace android {
namespace uirenderer {
@@ -31,7 +33,9 @@
}
AnimatedImageThread::AnimatedImageThread() {
+#ifdef __ANDROID__
setpriority(PRIO_PROCESS, 0, PRIORITY_NORMAL + PRIORITY_MORE_FAVORABLE);
+#endif
}
std::future<AnimatedImageDrawable::Snapshot> AnimatedImageThread::decodeNextFrame(
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index 90b1da8..0f80c55 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -25,7 +25,9 @@
#include <hwui/AnimatedImageDrawable.h>
#include <hwui/Canvas.h>
#include <hwui/ImageDecoder.h>
+#ifdef __ANDROID__
#include <utils/Looper.h>
+#endif
#include "ColorFilter.h"
#include "GraphicsJNI.h"
@@ -180,6 +182,23 @@
drawable->setRepetitionCount(loopCount);
}
+#ifndef __ANDROID__
+struct Message {
+ Message(int w) {}
+};
+
+class MessageHandler : public virtual RefBase {
+protected:
+ virtual ~MessageHandler() override {}
+
+public:
+ /**
+ * Handles a message.
+ */
+ virtual void handleMessage(const Message& message) = 0;
+};
+#endif
+
class InvokeListener : public MessageHandler {
public:
InvokeListener(JNIEnv* env, jobject javaObject) {
@@ -204,6 +223,7 @@
};
class JniAnimationEndListener : public OnAnimationEndListener {
+#ifdef __ANDROID__
public:
JniAnimationEndListener(sp<Looper>&& looper, JNIEnv* env, jobject javaObject) {
mListener = new InvokeListener(env, javaObject);
@@ -215,6 +235,17 @@
private:
sp<InvokeListener> mListener;
sp<Looper> mLooper;
+#else
+public:
+ JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
+ mListener = new InvokeListener(env, javaObject);
+ }
+
+ void onAnimationEnd() override { mListener->handleMessage(0); }
+
+private:
+ sp<InvokeListener> mListener;
+#endif
};
static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
@@ -223,6 +254,7 @@
if (!jdrawable) {
drawable->setOnAnimationEndListener(nullptr);
} else {
+#ifdef __ANDROID__
sp<Looper> looper = Looper::getForThread();
if (!looper.get()) {
doThrowISE(env,
@@ -233,6 +265,10 @@
drawable->setOnAnimationEndListener(
std::make_unique<JniAnimationEndListener>(std::move(looper), env, jdrawable));
+#else
+ drawable->setOnAnimationEndListener(
+ std::make_unique<JniAnimationEndListener>(env, jdrawable));
+#endif
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
index 9111e61..68c2244 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
@@ -23,6 +23,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.style.Hyphens
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import com.android.compose.theme.LocalAndroidColorScheme
@@ -39,7 +40,7 @@
text = text,
color = LocalAndroidColorScheme.current.onSurface,
textAlign = TextAlign.Center,
- style = MaterialTheme.typography.headlineSmall,
+ style = MaterialTheme.typography.headlineSmall.copy(hyphens = Hyphens.Auto),
)
}
@@ -52,7 +53,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = LocalAndroidColorScheme.current.onSurfaceVariant,
- style = MaterialTheme.typography.bodyMedium,
+ style = MaterialTheme.typography.bodyMedium.copy(hyphens = Hyphens.Auto),
)
}
@@ -70,7 +71,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = LocalAndroidColorScheme.current.onSurfaceVariant,
- style = MaterialTheme.typography.bodySmall,
+ style = MaterialTheme.typography.bodySmall.copy(hyphens = Hyphens.Auto),
overflow = TextOverflow.Ellipsis,
maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
onTextLayout = onTextLayout,
@@ -86,7 +87,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = LocalAndroidColorScheme.current.onSurface,
- style = MaterialTheme.typography.titleLarge,
+ style = MaterialTheme.typography.titleLarge.copy(hyphens = Hyphens.Auto),
)
}
@@ -104,7 +105,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = LocalAndroidColorScheme.current.onSurface,
- style = MaterialTheme.typography.titleSmall,
+ style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
overflow = TextOverflow.Ellipsis,
maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
onTextLayout = onTextLayout,
@@ -120,7 +121,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = color,
- style = MaterialTheme.typography.titleSmall,
+ style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
)
}
@@ -133,7 +134,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = MaterialTheme.colorScheme.inverseOnSurface,
- style = MaterialTheme.typography.bodyMedium,
+ style = MaterialTheme.typography.bodyMedium.copy(hyphens = Hyphens.Auto),
)
}
@@ -146,7 +147,7 @@
modifier = modifier.wrapContentSize(),
text = text,
color = MaterialTheme.colorScheme.inversePrimary,
- style = MaterialTheme.typography.labelLarge,
+ style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
)
}
@@ -160,7 +161,7 @@
text = text,
textAlign = TextAlign.Center,
color = LocalAndroidColorScheme.current.onSurfaceVariant,
- style = MaterialTheme.typography.labelLarge,
+ style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
)
}
@@ -173,6 +174,6 @@
modifier = modifier.wrapContentSize(),
text = text,
textAlign = TextAlign.Center,
- style = MaterialTheme.typography.labelLarge,
+ style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
)
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
similarity index 91%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index c308a98..2a2b2f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -85,7 +85,7 @@
}
@Test
- fun testIsImportantForAccessibility_falseWhenNoNotifs() =
+ fun isImportantForAccessibility_falseWhenNoNotifs() =
testScope.runTest {
val important by collectLastValue(underTest.isImportantForAccessibility)
@@ -100,7 +100,7 @@
}
@Test
- fun testIsImportantForAccessibility_trueWhenNotifs() =
+ fun isImportantForAccessibility_trueWhenNotifs() =
testScope.runTest {
val important by collectLastValue(underTest.isImportantForAccessibility)
@@ -115,7 +115,7 @@
}
@Test
- fun testIsImportantForAccessibility_trueWhenNotKeyguard() =
+ fun isImportantForAccessibility_trueWhenNotKeyguard() =
testScope.runTest {
val important by collectLastValue(underTest.isImportantForAccessibility)
@@ -130,7 +130,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_trueWhenNoNotifs() =
+ fun shouldIncludeEmptyShadeView_trueWhenNoNotifs() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -143,7 +143,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_falseWhenNotifs() =
+ fun shouldIncludeEmptyShadeView_falseWhenNotifs() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -156,7 +156,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
+ fun shouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -171,7 +171,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
+ fun shouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -189,7 +189,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_trueWhenLockedShade() =
+ fun shouldIncludeEmptyShadeView_trueWhenLockedShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -204,7 +204,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_falseWhenKeyguard() =
+ fun shouldIncludeEmptyShadeView_falseWhenKeyguard() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -219,7 +219,7 @@
}
@Test
- fun testShouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
+ fun shouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
@@ -236,7 +236,7 @@
}
@Test
- fun testAreNotificationsHiddenInShade_true() =
+ fun areNotificationsHiddenInShade_true() =
testScope.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
@@ -248,7 +248,7 @@
}
@Test
- fun testAreNotificationsHiddenInShade_false() =
+ fun areNotificationsHiddenInShade_false() =
testScope.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
@@ -260,7 +260,7 @@
}
@Test
- fun testHasFilteredOutSeenNotifications_true() =
+ fun hasFilteredOutSeenNotifications_true() =
testScope.runTest {
val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
@@ -271,7 +271,7 @@
}
@Test
- fun testHasFilteredOutSeenNotifications_false() =
+ fun hasFilteredOutSeenNotifications_false() =
testScope.runTest {
val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
@@ -282,7 +282,7 @@
}
@Test
- fun testShouldIncludeFooterView_trueWhenShade() =
+ fun shouldIncludeFooterView_trueWhenShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -298,7 +298,7 @@
}
@Test
- fun testShouldIncludeFooterView_trueWhenLockedShade() =
+ fun shouldIncludeFooterView_trueWhenLockedShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -314,7 +314,7 @@
}
@Test
- fun testShouldIncludeFooterView_falseWhenKeyguard() =
+ fun shouldIncludeFooterView_falseWhenKeyguard() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -329,7 +329,7 @@
}
@Test
- fun testShouldIncludeFooterView_falseWhenUserNotSetUp() =
+ fun shouldIncludeFooterView_falseWhenUserNotSetUp() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -347,7 +347,7 @@
}
@Test
- fun testShouldIncludeFooterView_falseWhenStartingToSleep() =
+ fun shouldIncludeFooterView_falseWhenStartingToSleep() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -365,7 +365,7 @@
}
@Test
- fun testShouldIncludeFooterView_falseWhenQsExpandedDefault() =
+ fun shouldIncludeFooterView_falseWhenQsExpandedDefault() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -384,7 +384,7 @@
}
@Test
- fun testShouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
+ fun shouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -405,7 +405,7 @@
}
@Test
- fun testShouldIncludeFooterView_falseWhenRemoteInputActive() =
+ fun shouldIncludeFooterView_falseWhenRemoteInputActive() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -423,7 +423,7 @@
}
@Test
- fun testShouldIncludeFooterView_animatesWhenShade() =
+ fun shouldIncludeFooterView_animatesWhenShade() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -439,7 +439,7 @@
}
@Test
- fun testShouldIncludeFooterView_notAnimatingOnKeyguard() =
+ fun shouldIncludeFooterView_notAnimatingOnKeyguard() =
testScope.runTest {
val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
@@ -455,7 +455,7 @@
}
@Test
- fun testShouldHideFooterView_trueWhenShadeIsClosed() =
+ fun shouldHideFooterView_trueWhenShadeIsClosed() =
testScope.runTest {
val shouldHide by collectLastValue(underTest.shouldHideFooterView)
@@ -469,7 +469,7 @@
}
@Test
- fun testShouldHideFooterView_falseWhenShadeIsOpen() =
+ fun shouldHideFooterView_falseWhenShadeIsOpen() =
testScope.runTest {
val shouldHide by collectLastValue(underTest.shouldHideFooterView)
@@ -484,7 +484,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testPinnedHeadsUpRows_filtersForPinnedItems() =
+ fun pinnedHeadsUpRows_filtersForPinnedItems() =
testScope.runTest {
val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
@@ -527,7 +527,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testHasPinnedHeadsUpRows_true() =
+ fun hasPinnedHeadsUpRows_true() =
testScope.runTest {
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
@@ -542,7 +542,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testHasPinnedHeadsUpRows_false() =
+ fun hasPinnedHeadsUpRows_false() =
testScope.runTest {
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
@@ -557,7 +557,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testTopHeadsUpRow_emptyList_null() =
+ fun topHeadsUpRow_emptyList_null() =
testScope.runTest {
val topHeadsUpRow by collectLastValue(underTest.topHeadsUpRow)
@@ -569,7 +569,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testHeadsUpAnimationsEnabled_true() =
+ fun headsUpAnimationsEnabled_true() =
testScope.runTest {
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
@@ -582,7 +582,7 @@
@Test
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
- fun testHeadsUpAnimationsEnabled_keyguardShowing_false() =
+ fun headsUpAnimationsEnabled_keyguardShowing_false() =
testScope.runTest {
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a293afc..182798e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -139,6 +139,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.ui.viewmodel.DreamViewModel;
import com.android.systemui.dump.DumpManager;
@@ -3404,7 +3405,8 @@
// Ensure that keyguard becomes visible if the going away animation is canceled
if (showKeyguard && !KeyguardWmStateRefactor.isEnabled()
- && MigrateClocksToBlueprint.isEnabled()) {
+ && (MigrateClocksToBlueprint.isEnabled()
+ || DeviceEntryUdfpsRefactor.isEnabled())) {
mKeyguardInteractor.showKeyguard();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 18bb5119..5544f93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -173,7 +173,6 @@
footerView,
footerViewModel,
clearAllNotifications = {
- metricsLogger.action(MetricsProto.MetricsEvent.ACTION_DISMISS_ALL_NOTES)
clearAllNotifications(
parentView,
// Hide the silent section header (if present) if there will be
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 97fc35a..8b7b348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -51,6 +51,9 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.BiometricUnlockInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
@@ -59,6 +62,7 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.SystemClock;
import dagger.Lazy;
@@ -286,7 +290,9 @@
VibratorHelper vibrator,
SystemClock systemClock,
Lazy<SelectedUserInteractor> selectedUserInteractor,
- BiometricUnlockInteractor biometricUnlockInteractor
+ BiometricUnlockInteractor biometricUnlockInteractor,
+ JavaAdapter javaAdapter,
+ KeyguardTransitionInteractor keyguardTransitionInteractor
) {
mPowerManager = powerManager;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -317,10 +323,19 @@
mOrderUnlockAndWake = resources.getBoolean(
com.android.internal.R.bool.config_orderUnlockAndWake);
mSelectedUserInteractor = selectedUserInteractor;
-
+ javaAdapter.alwaysCollectFlow(
+ keyguardTransitionInteractor.getStartedKeyguardTransitionStep(),
+ this::consumeTransitionStepOnStartedKeyguardState);
dumpManager.registerDumpable(this);
}
+ @VisibleForTesting
+ protected void consumeTransitionStepOnStartedKeyguardState(TransitionStep transitionStep) {
+ if (transitionStep.getFrom() == KeyguardState.GONE) {
+ mBiometricUnlockInteractor.setBiometricUnlockState(MODE_NONE);
+ }
+ }
+
public void setKeyguardViewController(KeyguardViewController keyguardViewController) {
mKeyguardViewController = keyguardViewController;
}
@@ -773,7 +788,6 @@
for (BiometricUnlockEventsListener listener : mBiometricUnlockEventsListeners) {
listener.onResetMode();
}
- mBiometricUnlockInteractor.setBiometricUnlockState(MODE_NONE);
mNumConsecutiveFpFailures = 0;
mLastFpFailureUptimeMillis = 0;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 6f65eb4..50f81ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.google.common.truth.Truth.assertThat;
@@ -26,6 +27,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -51,6 +53,10 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.BiometricUnlockInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -58,6 +64,7 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -158,7 +165,9 @@
mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper,
mSystemClock,
() -> mSelectedUserInteractor,
- mBiometricUnlockInteractor
+ mBiometricUnlockInteractor,
+ mock(JavaAdapter.class),
+ mock(KeyguardTransitionInteractor.class)
);
biometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
biometricUnlockController.addListener(mBiometricUnlockEventsListener);
@@ -462,6 +471,29 @@
}
@Test
+ public void biometricUnlockStateResetOnTransitionFromGone() {
+ mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+ new TransitionStep(
+ KeyguardState.AOD,
+ KeyguardState.GONE,
+ .1f /* value */,
+ TransitionState.STARTED
+ )
+ );
+ verify(mBiometricUnlockInteractor, never()).setBiometricUnlockState(anyInt());
+
+ mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+ new TransitionStep(
+ KeyguardState.GONE,
+ KeyguardState.AOD,
+ .1f /* value */,
+ TransitionState.STARTED
+ )
+ );
+ verify(mBiometricUnlockInteractor).setBiometricUnlockState(eq(MODE_NONE));
+ }
+
+ @Test
public void onFingerprintDetect_showBouncer() {
// WHEN fingerprint detect occurs
mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 9950d8f..da26209 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -1097,13 +1097,34 @@
return mBrightnessToBacklightSpline.interpolate(brightness);
}
- private float getBrightnessFromBacklight(float brightness) {
+ /**
+ * Calculates the screen brightness value - as used among the system from the HAL backlight
+ * level
+ * @param backlight value from 0-1 HAL scale
+ * @return brightness value from 0-1 framework scale
+ */
+ public float getBrightnessFromBacklight(float backlight) {
if (mLowBrightnessData != null) {
- return mLowBrightnessData.mBacklightToBrightness.interpolate(brightness);
+ return mLowBrightnessData.mBacklightToBrightness.interpolate(backlight);
}
- return mBacklightToBrightnessSpline.interpolate(brightness);
+ return mBacklightToBrightnessSpline.interpolate(backlight);
}
+ /**
+ *
+ * @return low brightness mode transition point
+ */
+ public float getLowBrightnessTransitionPoint() {
+ if (mLowBrightnessData == null) {
+ return PowerManager.BRIGHTNESS_MIN;
+ }
+ return mLowBrightnessData.mTransitionPoint;
+ }
+
+ /**
+ *
+ * @return HAL backlight mapping to framework brightness
+ */
private Spline getBacklightToBrightnessSpline() {
if (mLowBrightnessData != null) {
return mLowBrightnessData.mBacklightToBrightness;
@@ -1133,7 +1154,12 @@
return mBacklightToNitsSpline.interpolate(backlight);
}
- private float getBacklightFromNits(float nits) {
+ /**
+ *
+ * @param nits - display brightness
+ * @return corresponding HAL backlight value
+ */
+ public float getBacklightFromNits(float nits) {
if (mLowBrightnessData != null) {
return mLowBrightnessData.mNitsToBacklight.interpolate(nits);
}
@@ -1148,6 +1174,18 @@
}
/**
+ *
+ * @param lux - ambient brightness
+ * @return minimum allowed nits, given the lux.
+ */
+ public float getMinNitsFromLux(float lux) {
+ if (mLowBrightnessData == null) {
+ return INVALID_NITS;
+ }
+ return mLowBrightnessData.mMinLuxToNits.interpolate(lux);
+ }
+
+ /**
* @return true if there is sdrHdrRatioMap, false otherwise.
*/
public boolean hasSdrToHdrRatioSpline() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0807cc0..d99f712 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1336,12 +1336,14 @@
&& (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()
|| userSetBrightnessChanged);
- mBrightnessRangeController.setAutoBrightnessEnabled(
- mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()
+ final int autoBrightnessState = mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
: mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff()
? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
- : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+ : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
+
+ mBrightnessRangeController.setAutoBrightnessEnabled(autoBrightnessState);
+ mBrightnessClamperController.setAutoBrightnessState(autoBrightnessState);
boolean updateScreenBrightnessSetting =
displayBrightnessState.shouldUpdateScreenBrightnessSetting();
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index d8a4500..9c7504d 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -66,6 +66,7 @@
private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
@Nullable
private Type mClamperType = null;
+ private int mAutoBrightnessState = -1;
private boolean mClamperApplied = false;
@@ -94,7 +95,8 @@
mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags,
context);
- mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener);
+ mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener,
+ data.mDisplayDeviceConfig);
mOnPropertiesChangedListener =
properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
start();
@@ -197,6 +199,19 @@
mModifiers.forEach(modifier -> modifier.onAmbientLuxChange(ambientLux));
}
+ /**
+ * Sets the autobrightness state for clampers that need to be aware of the state.
+ * @param state autobrightness state
+ */
+ public void setAutoBrightnessState(int state) {
+ if (state == mAutoBrightnessState) {
+ return;
+ }
+ mModifiers.forEach(modifier -> modifier.setAutoBrightnessState(state));
+ mAutoBrightnessState = state;
+ recalculateBrightnessCap();
+ }
+
// Called in DisplayControllerHandler
private void recalculateBrightnessCap() {
float brightnessCap = PowerManager.BRIGHTNESS_MAX;
@@ -265,12 +280,14 @@
}
List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
- Handler handler, ClamperChangeListener listener) {
+ Handler handler, ClamperChangeListener listener,
+ DisplayDeviceConfig displayDeviceConfig) {
List<BrightnessStateModifier> modifiers = new ArrayList<>();
modifiers.add(new DisplayDimModifier(context));
modifiers.add(new BrightnessLowPowerModeModifier());
if (flags.isEvenDimmerEnabled()) {
- modifiers.add(new BrightnessLowLuxModifier(handler, listener, context));
+ modifiers.add(new BrightnessLowLuxModifier(handler, listener, context,
+ displayDeviceConfig));
}
return modifiers;
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
index a91bb59..7f88c30 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
@@ -16,13 +16,14 @@
package com.android.server.display.brightness.clamper;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
+
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.display.DisplayManagerInternal;
import android.net.Uri;
import android.os.Handler;
-import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -30,6 +31,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.utils.DebugUtils;
@@ -45,19 +47,23 @@
// 'adb shell setprop persist.log.tag.BrightnessLowLuxModifier DEBUG && adb reboot'
private static final String TAG = "BrightnessLowLuxModifier";
private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
- private static final float MIN_NITS = 2.0f;
+ private static final float MIN_NITS_DEFAULT = 0.2f;
private final SettingsObserver mSettingsObserver;
private final ContentResolver mContentResolver;
private final Handler mHandler;
private final BrightnessClamperController.ClamperChangeListener mChangeListener;
private int mReason;
private float mBrightnessLowerBound;
+ private float mMinNitsAllowed;
private boolean mIsActive;
+ private boolean mAutoBrightnessEnabled;
private float mAmbientLux;
+ private final DisplayDeviceConfig mDisplayDeviceConfig;
@VisibleForTesting
BrightnessLowLuxModifier(Handler handler,
- BrightnessClamperController.ClamperChangeListener listener, Context context) {
+ BrightnessClamperController.ClamperChangeListener listener, Context context,
+ DisplayDeviceConfig displayDeviceConfig) {
super();
mChangeListener = listener;
@@ -67,6 +73,8 @@
mHandler.post(() -> {
start();
});
+
+ mDisplayDeviceConfig = displayDeviceConfig;
}
/**
@@ -78,41 +86,45 @@
int userId = UserHandle.USER_CURRENT;
float settingNitsLowerBound = Settings.Secure.getFloatForUser(
mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS,
- /* def= */ MIN_NITS, userId);
+ /* def= */ MIN_NITS_DEFAULT, userId);
boolean isActive = Settings.Secure.getFloatForUser(mContentResolver,
Settings.Secure.EVEN_DIMMER_ACTIVATED,
- /* def= */ 0, userId) == 1.0f;
+ /* def= */ 0, userId) == 1.0f && mAutoBrightnessEnabled;
- // TODO: luxBasedNitsLowerBound = mMinLuxToNitsSpline(currentLux);
- float luxBasedNitsLowerBound = 2.0f;
+ float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
- final float nitsLowerBound = isActive ? Math.max(settingNitsLowerBound,
- luxBasedNitsLowerBound) : MIN_NITS;
+ final int reason;
+ float minNitsAllowed = -1f; // undefined, if setting is off.
+ final float minBrightnessAllowed;
- final int reason = settingNitsLowerBound > luxBasedNitsLowerBound
- ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND
- : BrightnessReason.MODIFIER_MIN_LUX;
+ if (isActive) {
+ minNitsAllowed = Math.max(settingNitsLowerBound,
+ luxBasedNitsLowerBound);
+ minBrightnessAllowed = getBrightnessFromNits(minNitsAllowed);
+ reason = settingNitsLowerBound > luxBasedNitsLowerBound
+ ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND
+ : BrightnessReason.MODIFIER_MIN_LUX;
+ } else {
+ minBrightnessAllowed = mDisplayDeviceConfig.getLowBrightnessTransitionPoint();
+ reason = 0;
+ }
- // TODO: brightnessLowerBound = nitsToBrightnessSpline(nitsLowerBound);
- final float brightnessLowerBound = PowerManager.BRIGHTNESS_MIN;
-
- if (mBrightnessLowerBound != brightnessLowerBound
+ if (mBrightnessLowerBound != minBrightnessAllowed
|| mReason != reason
|| mIsActive != isActive) {
mIsActive = isActive;
mReason = reason;
if (DEBUG) {
Slog.i(TAG, "isActive: " + isActive
- + ", brightnessLowerBound: " + brightnessLowerBound
+ + ", minBrightnessAllowed: " + minBrightnessAllowed
+ ", mAmbientLux: " + mAmbientLux
- + ", mReason: " + (
- mReason == BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND ? "minSetting"
- : "lux")
- + ", nitsLowerBound: " + nitsLowerBound
+ + ", mReason: " + (mReason)
+ + ", minNitsAllowed: " + minNitsAllowed
);
}
- mBrightnessLowerBound = brightnessLowerBound;
+ mMinNitsAllowed = minNitsAllowed;
+ mBrightnessLowerBound = minBrightnessAllowed;
mChangeListener.onChanged();
}
}
@@ -177,11 +189,23 @@
}
@Override
+ public void setAutoBrightnessState(int state) {
+ mAutoBrightnessEnabled = state == AUTO_BRIGHTNESS_ENABLED;
+ }
+
+ @Override
public void dump(PrintWriter pw) {
pw.println("BrightnessLowLuxModifier:");
pw.println(" mIsActive=" + mIsActive);
pw.println(" mBrightnessLowerBound=" + mBrightnessLowerBound);
pw.println(" mReason=" + mReason);
+ pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mMinNitsAllowed=" + mMinNitsAllowed);
+ }
+
+ private float getBrightnessFromNits(float nits) {
+ return mDisplayDeviceConfig.getBrightnessFromBacklight(
+ mDisplayDeviceConfig.getBacklightFromNits(nits));
}
private final class SettingsObserver extends ContentObserver {
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
index 2a3dd87..db5a524d 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
@@ -73,4 +73,9 @@
public void onAmbientLuxChange(float ambientLux) {
// do nothing
}
+
+ @Override
+ public void setAutoBrightnessState(int state) {
+ // do nothing
+ }
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
index 2234258..1606159c 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
@@ -48,4 +48,10 @@
* @param ambientLux current debounced lux.
*/
void onAmbientLuxChange(float ambientLux);
+
+ /**
+ * Sets the autobrightness state for clampers that need to be aware of the state.
+ * @param state autobrightness state
+ */
+ void setAutoBrightnessState(int state);
}
diff --git a/services/core/java/com/android/server/display/config/LowBrightnessData.java b/services/core/java/com/android/server/display/config/LowBrightnessData.java
index aa82533..1a4e807 100644
--- a/services/core/java/com/android/server/display/config/LowBrightnessData.java
+++ b/services/core/java/com/android/server/display/config/LowBrightnessData.java
@@ -66,11 +66,13 @@
* Spline, mapping between backlight and brightness
*/
public final Spline mBacklightToBrightness;
+ public final Spline mMinLuxToNits;
@VisibleForTesting
public LowBrightnessData(float transitionPoint, float[] nits,
float[] backlight, float[] brightness, Spline backlightToNits,
- Spline nitsToBacklight, Spline brightnessToBacklight, Spline backlightToBrightness) {
+ Spline nitsToBacklight, Spline brightnessToBacklight, Spline backlightToBrightness,
+ Spline minLuxToNits) {
mTransitionPoint = transitionPoint;
mNits = nits;
mBacklight = backlight;
@@ -79,6 +81,7 @@
mNitsToBacklight = nitsToBacklight;
mBrightnessToBacklight = brightnessToBacklight;
mBacklightToBrightness = backlightToBrightness;
+ mMinLuxToNits = minLuxToNits;
}
@Override
@@ -92,6 +95,7 @@
+ ", mNitsToBacklight: " + mNitsToBacklight
+ ", mBrightnessToBacklight: " + mBrightnessToBacklight
+ ", mBacklightToBrightness: " + mBacklightToBrightness
+ + ", mMinLuxToNits: " + mMinLuxToNits
+ "} ";
}
@@ -132,11 +136,40 @@
brightness[i] = brightnessList.get(i);
}
+ final NitsMap map = lbm.getLuxToMinimumNitsMap();
+ if (map == null) {
+ Slog.e(TAG, "Invalid min lux to nits mapping");
+ return null;
+ }
+ final List<Point> points = map.getPoint();
+ final int size = points.size();
+
+ float[] minLux = new float[size];
+ float[] minNits = new float[size];
+
+ int i = 0;
+ for (Point point : points) {
+ minLux[i] = point.getValue().floatValue();
+ minNits[i] = point.getNits().floatValue();
+ if (i > 0) {
+ if (minLux[i] < minLux[i - 1]) {
+ Slog.e(TAG, "minLuxToNitsSpline must be non-decreasing, ignoring rest "
+ + " of configuration. Value: " + minLux[i] + " < " + minLux[i - 1]);
+ }
+ if (minNits[i] < minNits[i - 1]) {
+ Slog.e(TAG, "minLuxToNitsSpline must be non-decreasing, ignoring rest "
+ + " of configuration. Nits: " + minNits[i] + " < " + minNits[i - 1]);
+ }
+ }
+ ++i;
+ }
+
return new LowBrightnessData(transitionPoints, nits, backlight, brightness,
Spline.createSpline(backlight, nits),
Spline.createSpline(nits, backlight),
Spline.createSpline(brightness, backlight),
- Spline.createSpline(backlight, brightness)
- );
+ Spline.createSpline(backlight, brightness),
+ Spline.createSpline(minLux, minNits)
+ );
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index 097daf2..5563cae 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Flags.updateRankingTime;
import static android.app.Notification.FLAG_INSISTENT;
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.NotificationManager.IMPORTANCE_MIN;
@@ -496,6 +497,11 @@
Slog.v(TAG, "INTERRUPTIVENESS: "
+ record.getKey() + " is interruptive: alerted");
}
+ if (updateRankingTime()) {
+ if (buzz || beep) {
+ record.resetRankingTime();
+ }
+ }
}
}
final int buzzBeepBlinkLoggingCode =
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9fcdfdd..ca3db2c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -142,6 +142,7 @@
import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.app.Flags.updateRankingTime;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -238,9 +239,6 @@
import android.database.ContentObserver;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioManagerInternal;
-import android.media.IRingtonePlayer;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
@@ -612,8 +610,7 @@
PackageManagerInternal mPackageManagerInternal;
private PermissionManager mPermissionManager;
private PermissionPolicyInternal mPermissionPolicyInternal;
- AudioManager mAudioManager;
- AudioManagerInternal mAudioManagerInternal;
+
// Can be null for wear
@Nullable StatusBarManagerInternal mStatusBar;
private WindowManagerInternal mWindowManagerInternal;
@@ -641,34 +638,12 @@
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
- private LogicalLight mNotificationLight;
- LogicalLight mAttentionLight;
-
- private boolean mUseAttentionLight;
- boolean mHasLight = true;
- boolean mSystemReady;
-
- private boolean mDisableNotificationEffects;
- private int mCallState;
- private String mSoundNotificationKey;
- private String mVibrateNotificationKey;
-
private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
new SparseArray<>();
private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
private int mListenerHints; // right now, all hints are global
private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
- // for enabling and disabling notification pulse behavior
- boolean mScreenOn = true;
- protected boolean mInCallStateOffHook = false;
- boolean mNotificationPulseEnabled;
-
- private Uri mInCallNotificationUri;
- private AudioAttributes mInCallNotificationAudioAttributes;
- private float mInCallNotificationVolume;
- private Binder mCallNotificationToken = null;
-
private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
// used as a mutex for access to all active notifications & listeners
@@ -696,11 +671,6 @@
// Used for rate limiting toasts by package.
private MultiRateLimiter mToastRateLimiter;
- private KeyguardManager mKeyguardManager;
-
- // The last key in this list owns the hardware.
- ArrayList<String> mLights = new ArrayList<>();
-
private AppOpsManager mAppOps;
private UsageStatsManagerInternal mAppUsageStats;
private DevicePolicyManagerInternal mDpm;
@@ -725,7 +695,6 @@
RankingHelper mRankingHelper;
@VisibleForTesting
PreferencesHelper mPreferencesHelper;
- private VibratorHelper mVibratorHelper;
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
@@ -751,8 +720,6 @@
private GroupHelper mGroupHelper;
private int mAutoGroupAtCount;
private boolean mIsTelevision;
- private boolean mIsAutomotive;
- private boolean mNotificationEffectsEnabledForAutomotive;
private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
protected NotificationAttentionHelper mAttentionHelper;
@@ -1270,17 +1237,7 @@
@Override
public void onSetDisabled(int status) {
synchronized (mNotificationLock) {
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.updateDisableNotificationEffectsLocked(status);
- } else {
- mDisableNotificationEffects =
- (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
- if (disableNotificationEffects(null) != null) {
- // cancel whatever's going on
- clearSoundLocked();
- clearVibrateLocked();
- }
- }
+ mAttentionHelper.updateDisableNotificationEffectsLocked(status);
}
}
@@ -1421,13 +1378,7 @@
public void clearEffects() {
synchronized (mNotificationLock) {
if (DBG) Slog.d(TAG, "clearEffects");
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.clearAttentionEffects();
- } else {
- clearSoundLocked();
- clearVibrateLocked();
- clearLightsLocked();
- }
+ mAttentionHelper.clearAttentionEffects();
}
}
@@ -1695,11 +1646,7 @@
int changedFlags = data.getFlags() ^ flags;
if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
// Suppress notification flag changed, clear any effects
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.clearEffectsLocked(key);
- } else {
- clearEffectsLocked(key);
- }
+ mAttentionHelper.clearEffectsLocked(key);
}
data.setFlags(flags);
// Shouldn't alert again just because of a flag change.
@@ -1832,53 +1779,6 @@
hasSensitiveContent, lifespanMs);
}
- @GuardedBy("mNotificationLock")
- void clearSoundLocked() {
- mSoundNotificationKey = null;
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- player.stopAsync();
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @GuardedBy("mNotificationLock")
- void clearVibrateLocked() {
- mVibrateNotificationKey = null;
- final long identity = Binder.clearCallingIdentity();
- try {
- mVibratorHelper.cancelVibration();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @GuardedBy("mNotificationLock")
- private void clearLightsLocked() {
- // light
- mLights.clear();
- updateLightsLocked();
- }
-
- @GuardedBy("mNotificationLock")
- private void clearEffectsLocked(String key) {
- if (key.equals(mSoundNotificationKey)) {
- clearSoundLocked();
- }
- if (key.equals(mVibrateNotificationKey)) {
- clearVibrateLocked();
- }
- boolean removed = mLights.remove(key);
- if (removed) {
- updateLightsLocked();
- }
- }
-
protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -2068,27 +1968,6 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (!Flags.refactorAttentionHelper()) {
- if (action.equals(Intent.ACTION_SCREEN_ON)) {
- // Keep track of screen on/off state, but do not turn off the notification light
- // until user passes through the lock screen or views the notification.
- mScreenOn = true;
- updateNotificationPulse();
- } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- mScreenOn = false;
- updateNotificationPulse();
- } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
- mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
- .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
- updateNotificationPulse();
- } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
- // turn off LED when user passes through lock screen
- if (mNotificationLight != null) {
- mNotificationLight.turnOff();
- }
- }
- }
-
if (action.equals(Intent.ACTION_USER_STOPPED)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
@@ -2164,8 +2043,6 @@
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
private final Uri NOTIFICATION_BUBBLES_URI
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
- private final Uri NOTIFICATION_LIGHT_PULSE_URI
- = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
private final Uri NOTIFICATION_RATE_LIMIT_URI
= Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
private final Uri NOTIFICATION_HISTORY_ENABLED
@@ -2188,10 +2065,6 @@
ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
false, this, UserHandle.USER_ALL);
- if (!Flags.refactorAttentionHelper()) {
- resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
- false, this, UserHandle.USER_ALL);
- }
resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
@@ -2218,17 +2091,6 @@
public void update(Uri uri) {
ContentResolver resolver = getContext().getContentResolver();
- if (!Flags.refactorAttentionHelper()) {
- if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
- boolean pulseEnabled = Settings.System.getIntForUser(resolver,
- Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
- != 0;
- if (mNotificationPulseEnabled != pulseEnabled) {
- mNotificationPulseEnabled = pulseEnabled;
- updateNotificationPulse();
- }
- }
- }
if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
@@ -2347,21 +2209,11 @@
// TODO - replace these methods with new fields in the VisibleForTesting constructor
@VisibleForTesting
- void setAudioManager(AudioManager audioManager) {
- mAudioManager = audioManager;
- }
-
- @VisibleForTesting
void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
mStrongAuthTracker = strongAuthTracker;
}
@VisibleForTesting
- void setKeyguardManager(KeyguardManager keyguardManager) {
- mKeyguardManager = keyguardManager;
- }
-
- @VisibleForTesting
ShortcutHelper getShortcutHelper() {
return mShortcutHelper;
}
@@ -2372,33 +2224,6 @@
}
@VisibleForTesting
- VibratorHelper getVibratorHelper() {
- return mVibratorHelper;
- }
-
- @VisibleForTesting
- void setVibratorHelper(VibratorHelper helper) {
- mVibratorHelper = helper;
- }
-
- @VisibleForTesting
- void setHints(int hints) {
- mListenerHints = hints;
- }
-
- @VisibleForTesting
- void setLights(LogicalLight light) {
- mNotificationLight = light;
- mAttentionLight = light;
- mNotificationPulseEnabled = true;
- }
-
- @VisibleForTesting
- void setScreenOn(boolean on) {
- mScreenOn = on;
- }
-
- @VisibleForTesting
int getNotificationRecordCount() {
synchronized (mNotificationLock) {
int count = mNotificationList.size() + mNotificationsByKey.size()
@@ -2446,12 +2271,6 @@
return mNotificationsByKey.get(key);
}
-
- @VisibleForTesting
- void setSystemReady(boolean systemReady) {
- mSystemReady = systemReady;
- }
-
@VisibleForTesting
void setHandler(WorkerHandler handler) {
mHandler = handler;
@@ -2471,13 +2290,8 @@
}
@VisibleForTesting
- void setIsAutomotive(boolean isAutomotive) {
- mIsAutomotive = isAutomotive;
- }
-
- @VisibleForTesting
- void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) {
- mNotificationEffectsEnabledForAutomotive = isEnabled;
+ void setAttentionHelper(NotificationAttentionHelper nah) {
+ mAttentionHelper = nah;
}
@VisibleForTesting
@@ -2486,16 +2300,6 @@
}
@VisibleForTesting
- void setUsageStats(NotificationUsageStats us) {
- mUsageStats = us;
- }
-
- @VisibleForTesting
- void setAccessibilityManager(AccessibilityManager am) {
- mAccessibilityManager = am;
- }
-
- @VisibleForTesting
void setTelecomManager(TelecomManager tm) {
mTelecomManager = tm;
}
@@ -2513,7 +2317,7 @@
DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
NotificationHistoryManager historyManager, StatsManager statsManager,
- TelephonyManager telephonyManager, ActivityManagerInternal ami,
+ ActivityManagerInternal ami,
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
UsageStatsManagerInternal usageStatsManagerInternal,
TelecomManager telecomManager, NotificationChannelLogger channelLogger,
@@ -2645,7 +2449,6 @@
extractorNames);
mSnoozeHelper = snoozeHelper;
mGroupHelper = groupHelper;
- mVibratorHelper = new VibratorHelper(getContext());
mHistoryManager = historyManager;
// This is a ManagedServices object that keeps track of the listeners.
@@ -2664,43 +2467,9 @@
mStatusBar.setNotificationDelegate(mNotificationDelegate);
}
- mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
- mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
-
- mInCallNotificationUri = Uri.parse("file://" +
- resources.getString(R.string.config_inCallNotificationSound));
- mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
- .build();
- mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
-
- mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
- mHasLight =
- resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
-
- // Don't start allowing notifications until the setup wizard has run once.
- // After that, including subsequent boots, init with notifications turned on.
- // This works on the first boot because the setup wizard will toggle this
- // flag at least once and we'll go back to 0 after that.
- if (0 == Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0)) {
- mDisableNotificationEffects = true;
- }
mZenModeHelper.initZenMode();
mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
- if (mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- telephonyManager.listen(new PhoneStateListener() {
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- if (mCallState == state) return;
- if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
- mCallState = state;
- }
- }, PhoneStateListener.LISTEN_CALL_STATE);
- }
-
mSettingsObserver = new SettingsObserver(mHandler);
mArchive = new Archive(resources.getInteger(
@@ -2709,11 +2478,6 @@
mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
|| mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
- mIsAutomotive =
- mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
- mNotificationEffectsEnabledForAutomotive =
- resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
-
mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
@@ -2733,22 +2497,14 @@
mToastRateLimiter = toastRateLimiter;
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
+ mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
mAccessibilityManager, mPackageManagerClient, userManager, usageStats,
mNotificationManagerPrivate, mZenModeHelper, flagResolver);
- }
// register for various Intents.
// If this is called within a test, make sure to unregister the intent receivers by
// calling onDestroy()
IntentFilter filter = new IntentFilter();
- if (!Flags.refactorAttentionHelper()) {
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
- }
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
@@ -2874,7 +2630,6 @@
new NotificationHistoryManager(getContext(), handler),
mStatsManager = (StatsManager) getContext().getSystemService(
Context.STATS_MANAGER),
- getContext().getSystemService(TelephonyManager.class),
LocalServices.getService(ActivityManagerInternal.class),
createToastRateLimiter(), new PermissionHelper(getContext(),
AppGlobals.getPackageManager(),
@@ -3054,14 +2809,7 @@
@VisibleForTesting
void onBootPhase(int phase, Looper mainLooper) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- // no beeping until we're basically done booting
- mSystemReady = true;
-
- // Grab our optional AudioService
- mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
- mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady();
RoleObserver roleObserver = new RoleObserver(getContext(),
getContext().getSystemService(RoleManager.class),
@@ -3080,9 +2828,7 @@
}
registerNotificationPreferencesPullers();
new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.onSystemReady();
- }
+ mAttentionHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -6866,33 +6612,6 @@
return null;
}
- private String disableNotificationEffects(NotificationRecord record) {
- if (mDisableNotificationEffects) {
- return "booleanState";
- }
- if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
- return "listenerHints";
- }
- if (record != null && record.getAudioAttributes() != null) {
- if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
- if (record.getAudioAttributes().getUsage()
- != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
- return "listenerNoti";
- }
- }
- if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
- if (record.getAudioAttributes().getUsage()
- == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
- return "listenerCall";
- }
- }
- }
- if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
- return "callState";
- }
- return null;
- }
-
// Gets packages that have requested notification permission, and whether that has been
// allowed/denied, for all users on the device.
// Returns a single map containing that info keyed by (uid, package name) for all users.
@@ -7061,33 +6780,10 @@
dumpNotificationRecords(pw, filter);
}
if (!filter.filtered) {
- N = mLights.size();
- if (N > 0) {
- pw.println(" Lights List:");
- for (int i=0; i<N; i++) {
- if (i == N - 1) {
- pw.print(" > ");
- } else {
- pw.print(" ");
- }
- pw.println(mLights.get(i));
- }
- pw.println(" ");
- }
- pw.println(" mUseAttentionLight=" + mUseAttentionLight);
- pw.println(" mHasLight=" + mHasLight);
- pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
- pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
- pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
- pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
- pw.println(" mCallState=" + callStateToString(mCallState));
- pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
pw.println(" hideSilentStatusBar="
+ mPreferencesHelper.shouldHideSilentStatusIcons());
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.dump(pw, " ", filter);
- }
+ mAttentionHelper.dump(pw, " ", filter);
}
pw.println(" mArchive=" + mArchive.toString());
mArchive.dumpImpl(pw, filter);
@@ -8379,11 +8075,7 @@
boolean wasPosted = removeFromNotificationListsLocked(r);
cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null,
SystemClock.elapsedRealtime());
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.updateLightsLocked();
- } else {
- updateLightsLocked();
- }
+ mAttentionHelper.updateLightsLocked();
if (isSnoozable(r)) {
if (mSnoozeCriterionId != null) {
mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId);
@@ -8519,11 +8211,7 @@
cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
mSendDelete, childrenFlagChecker, mReason,
mCancellationElapsedTimeMs);
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.updateLightsLocked();
- } else {
- updateLightsLocked();
- }
+ mAttentionHelper.updateLightsLocked();
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
true /* isRemoved */,
@@ -8802,6 +8490,11 @@
r.isUpdate = true;
final boolean isInterruptive = isVisuallyInterruptive(old, r);
r.setTextChanged(isInterruptive);
+ if (updateRankingTime()) {
+ if (isInterruptive) {
+ r.resetRankingTime();
+ }
+ }
}
mNotificationsByKey.put(n.getKey(), r);
@@ -8818,14 +8511,10 @@
int buzzBeepBlinkLoggingCode = 0;
if (!r.isHidden()) {
- if (Flags.refactorAttentionHelper()) {
- buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
+ buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
new NotificationAttentionHelper.Signals(
- mUserProfiles.isCurrentProfile(r.getUserId()),
- mListenerHints));
- } else {
- buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
- }
+ mUserProfiles.isCurrentProfile(r.getUserId()),
+ mListenerHints));
}
if (notification.getSmallIcon() != null) {
@@ -9150,425 +8839,6 @@
}
}
- @VisibleForTesting
- @GuardedBy("mNotificationLock")
- /**
- * Determine whether this notification should attempt to make noise, vibrate, or flash the LED
- * @return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)
- */
- int buzzBeepBlinkLocked(NotificationRecord record) {
- if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
- return 0;
- }
- boolean buzz = false;
- boolean beep = false;
- boolean blink = false;
-
- final String key = record.getKey();
-
- // Should this notification make noise, vibe, or use the LED?
- final boolean aboveThreshold =
- mIsAutomotive
- ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
- : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
- // Remember if this notification already owns the notification channels.
- boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
- boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
- // These are set inside the conditional if the notification is allowed to make noise.
- boolean hasValidVibrate = false;
- boolean hasValidSound = false;
- boolean sentAccessibilityEvent = false;
-
- // If the notification will appear in the status bar, it should send an accessibility event
- final boolean suppressedByDnd = record.isIntercepted()
- && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
- if (!record.isUpdate
- && record.getImportance() > IMPORTANCE_MIN
- && !suppressedByDnd
- && isNotificationForCurrentUser(record)) {
- sendAccessibilityEvent(record);
- sentAccessibilityEvent = true;
- }
-
- if (aboveThreshold && isNotificationForCurrentUser(record)) {
- if (mSystemReady && mAudioManager != null) {
- Uri soundUri = record.getSound();
- hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
- VibrationEffect vibration = record.getVibration();
- // Demote sound to vibration if vibration missing & phone in vibration mode.
- if (vibration == null
- && hasValidSound
- && (mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_VIBRATE)
- && mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
- boolean insistent = (record.getFlags() & Notification.FLAG_INSISTENT) != 0;
- vibration = mVibratorHelper.createFallbackVibration(insistent);
- }
- hasValidVibrate = vibration != null;
- boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
- if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
- if (!sentAccessibilityEvent) {
- sendAccessibilityEvent(record);
- sentAccessibilityEvent = true;
- }
- if (DBG) Slog.v(TAG, "Interrupting!");
- boolean isInsistentUpdate = isInsistentUpdate(record);
- if (hasValidSound) {
- if (isInsistentUpdate) {
- // don't reset insistent sound, it's jarring
- beep = true;
- } else {
- if (isInCall()) {
- playInCallNotification();
- beep = true;
- } else {
- beep = playSound(record, soundUri);
- }
- if (beep) {
- mSoundNotificationKey = key;
- }
- }
- }
-
- final boolean ringerModeSilent =
- mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_SILENT;
- if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
- if (isInsistentUpdate) {
- buzz = true;
- } else {
- buzz = playVibration(record, vibration, hasValidSound);
- if (buzz) {
- mVibrateNotificationKey = key;
- }
- }
- }
-
- // Try to start flash notification event whenever an audible and non-suppressed
- // notification is received
- mAccessibilityManager.startFlashNotificationEvent(getContext(),
- AccessibilityManager.FLASH_REASON_NOTIFICATION,
- record.getSbn().getPackageName());
-
- } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
- hasValidSound = false;
- }
- }
- }
- // If a notification is updated to remove the actively playing sound or vibrate,
- // cancel that feedback now
- if (wasBeep && !hasValidSound) {
- clearSoundLocked();
- }
- if (wasBuzz && !hasValidVibrate) {
- clearVibrateLocked();
- }
-
- // light
- // release the light
- boolean wasShowLights = mLights.remove(key);
- if (canShowLightsLocked(record, aboveThreshold)) {
- mLights.add(key);
- updateLightsLocked();
- if (mUseAttentionLight && mAttentionLight != null) {
- mAttentionLight.pulse();
- }
- blink = true;
- } else if (wasShowLights) {
- updateLightsLocked();
- }
- final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
- if (buzzBeepBlink > 0) {
- // Ignore summary updates because we don't display most of the information.
- if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {
- if (DEBUG_INTERRUPTIVENESS) {
- Slog.v(TAG, "INTERRUPTIVENESS: "
- + record.getKey() + " is not interruptive: summary");
- }
- } else if (record.canBubble()) {
- if (DEBUG_INTERRUPTIVENESS) {
- Slog.v(TAG, "INTERRUPTIVENESS: "
- + record.getKey() + " is not interruptive: bubble");
- }
- } else {
- record.setInterruptive(true);
- if (DEBUG_INTERRUPTIVENESS) {
- Slog.v(TAG, "INTERRUPTIVENESS: "
- + record.getKey() + " is interruptive: alerted");
- }
- }
- MetricsLogger.action(record.getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_ALERT)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(buzzBeepBlink));
- EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0, 0);
- }
- record.setAudiblyAlerted(buzz || beep);
- return buzzBeepBlink;
- }
-
- @GuardedBy("mNotificationLock")
- boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
- // device lacks light
- if (!mHasLight) {
- return false;
- }
- // user turned lights off globally
- if (!mNotificationPulseEnabled) {
- return false;
- }
- // the notification/channel has no light
- if (record.getLight() == null) {
- return false;
- }
- // unimportant notification
- if (!aboveThreshold) {
- return false;
- }
- // suppressed due to DND
- if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
- return false;
- }
- // Suppressed because it's a silent update
- final Notification notification = record.getNotification();
- if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
- return false;
- }
- // Suppressed because another notification in its group handles alerting
- if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
- return false;
- }
- // not if in call
- if (isInCall()) {
- return false;
- }
- // check current user
- if (!isNotificationForCurrentUser(record)) {
- return false;
- }
- // Light, but only when the screen is off
- return true;
- }
-
- @GuardedBy("mNotificationLock")
- boolean isInsistentUpdate(final NotificationRecord record) {
- return (Objects.equals(record.getKey(), mSoundNotificationKey)
- || Objects.equals(record.getKey(), mVibrateNotificationKey))
- && isCurrentlyInsistent();
- }
-
- @GuardedBy("mNotificationLock")
- boolean isCurrentlyInsistent() {
- return isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
- || isLoopingRingtoneNotification(mNotificationsByKey.get(mVibrateNotificationKey));
- }
-
- @GuardedBy("mNotificationLock")
- boolean shouldMuteNotificationLocked(final NotificationRecord record) {
- // Suppressed because it's a silent update
- final Notification notification = record.getNotification();
- if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
- return true;
- }
-
- // Suppressed because a user manually unsnoozed something (or similar)
- if (record.shouldPostSilently()) {
- return true;
- }
-
- // muted by listener
- final String disableEffects = disableNotificationEffects(record);
- if (disableEffects != null) {
- ZenLog.traceDisableEffects(record, disableEffects);
- return true;
- }
-
- // suppressed due to DND
- if (record.isIntercepted()) {
- return true;
- }
-
- // Suppressed because another notification in its group handles alerting
- if (record.getSbn().isGroup()) {
- if (notification.suppressAlertingDueToGrouping()) {
- return true;
- }
- }
-
- // Suppressed for being too recently noisy
- final String pkg = record.getSbn().getPackageName();
- if (mUsageStats.isAlertRateLimited(pkg)) {
- Slog.e(TAG, "Muting recently noisy " + record.getKey());
- return true;
- }
-
- // A different looping ringtone, such as an incoming call is playing
- if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
- return true;
- }
-
- // Suppressed since it's a non-interruptive update to a bubble-suppressed notification
- final boolean isBubbleOrOverflowed = record.canBubble() && (record.isFlagBubbleRemoved()
- || record.getNotification().isBubbleNotification());
- if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed
- && record.getNotification().getBubbleMetadata() != null) {
- if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) {
- return true;
- }
- }
-
- return false;
- }
-
- @GuardedBy("mNotificationLock")
- private boolean isLoopingRingtoneNotification(final NotificationRecord playingRecord) {
- if (playingRecord != null) {
- if (playingRecord.getAudioAttributes().getUsage() == USAGE_NOTIFICATION_RINGTONE
- && (playingRecord.getNotification().flags & FLAG_INSISTENT) != 0) {
- return true;
- }
- }
- return false;
- }
-
- private boolean playSound(final NotificationRecord record, Uri soundUri) {
- final boolean shouldPlay;
- if (focusExclusiveWithRecording()) {
- // flagged path
- shouldPlay = mAudioManager.shouldNotificationSoundPlay(record.getAudioAttributes());
- } else {
- // legacy path
- // play notifications if there is no user of exclusive audio focus
- // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
- // VIBRATE ringer mode)
- shouldPlay = !mAudioManager.isAudioFocusExclusive()
- && (mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0);
- }
- if (!shouldPlay) {
- if (DBG) Slog.v(TAG, "Not playing sound " + soundUri + " due to focus/volume");
- return false;
- }
-
- boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0;
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (DBG) {
- Slog.v(TAG, "Playing sound " + soundUri
- + " with attributes " + record.getAudioAttributes());
- }
- player.playAsync(soundUri, record.getSbn().getUser(), looping,
- record.getAudioAttributes(), 1.0f);
- return true;
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return false;
- }
-
- private boolean playVibration(final NotificationRecord record, final VibrationEffect effect,
- boolean delayVibForSound) {
- // Escalate privileges so we can use the vibrator even if the
- // notifying app does not have the VIBRATE permission.
- final long identity = Binder.clearCallingIdentity();
- try {
- if (delayVibForSound) {
- new Thread(() -> {
- // delay the vibration by the same amount as the notification sound
- final int waitMs = mAudioManager.getFocusRampTimeMs(
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
- record.getAudioAttributes());
- if (DBG) {
- Slog.v(TAG, "Delaying vibration for notification "
- + record.getKey() + " by " + waitMs + "ms");
- }
- try {
- Thread.sleep(waitMs);
- } catch (InterruptedException e) { }
- // Notifications might be canceled before it actually vibrates due to waitMs,
- // so need to check that the notification is still valid for vibrate.
- synchronized (mNotificationLock) {
- if (mNotificationsByKey.get(record.getKey()) != null) {
- if (record.getKey().equals(mVibrateNotificationKey)) {
- vibrate(record, effect, true);
- } else {
- if (DBG) {
- Slog.v(TAG, "No vibration for notification "
- + record.getKey() + ": a new notification is "
- + "vibrating, or effects were cleared while waiting");
- }
- }
- } else {
- Slog.w(TAG, "No vibration for canceled notification "
- + record.getKey());
- }
- }
- }).start();
- } else {
- vibrate(record, effect, false);
- }
- return true;
- } finally{
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- private void vibrate(NotificationRecord record, VibrationEffect effect, boolean delayed) {
- // We need to vibrate as "android" so we can breakthrough DND. VibratorManagerService
- // doesn't have a concept of vibrating on an app's behalf, so add the app information
- // to the reason so we can still debug from bugreports
- String reason = "Notification (" + record.getSbn().getOpPkg() + " "
- + record.getSbn().getUid() + ") " + (delayed ? "(Delayed)" : "");
- mVibratorHelper.vibrate(effect, record.getAudioAttributes(), reason);
- }
-
- private boolean isNotificationForCurrentUser(NotificationRecord record) {
- final int currentUser;
- final long token = Binder.clearCallingIdentity();
- try {
- currentUser = ActivityManager.getCurrentUser();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return (record.getUserId() == UserHandle.USER_ALL ||
- record.getUserId() == currentUser ||
- mUserProfiles.isCurrentProfile(record.getUserId()));
- }
-
- protected void playInCallNotification() {
- final ContentResolver cr = getContext().getContentResolver();
- if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
- && Settings.Secure.getIntForUser(cr,
- Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1, cr.getUserId()) != 0) {
- new Thread() {
- @Override
- public void run() {
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (mCallNotificationToken != null) {
- player.stop(mCallNotificationToken);
- }
- mCallNotificationToken = new Binder();
- player.play(mCallNotificationToken, mInCallNotificationUri,
- mInCallNotificationAudioAttributes,
- mInCallNotificationVolume, false);
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }.start();
- }
- }
-
@GuardedBy("mToastQueue")
void showNextToastLocked(boolean lastToastWasTextRecord) {
if (mIsCurrentToastShown) {
@@ -9840,13 +9110,10 @@
|| interruptiveChanged;
if (interceptBefore && !record.isIntercepted()
&& record.isNewEnoughForAlerting(System.currentTimeMillis())) {
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.buzzBeepBlinkLocked(record,
- new NotificationAttentionHelper.Signals(
- mUserProfiles.isCurrentProfile(record.getUserId()), mListenerHints));
- } else {
- buzzBeepBlinkLocked(record);
- }
+
+ mAttentionHelper.buzzBeepBlinkLocked(record,
+ new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile(
+ record.getUserId()), mListenerHints));
// Log alert after change in intercepted state to Zen Log as well
ZenLog.traceAlertOnUpdatedIntercept(record);
@@ -10113,37 +9380,6 @@
return (x < low) ? low : ((x > high) ? high : x);
}
- void sendAccessibilityEvent(NotificationRecord record) {
- if (!mAccessibilityManager.isEnabled()) {
- return;
- }
-
- final Notification notification = record.getNotification();
- final CharSequence packageName = record.getSbn().getPackageName();
- final AccessibilityEvent event =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
- event.setPackageName(packageName);
- event.setClassName(Notification.class.getName());
- final int visibilityOverride = record.getPackageVisibilityOverride();
- final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
- ? notification.visibility : visibilityOverride;
- final int userId = record.getUser().getIdentifier();
- final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
- if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
- // Emit the public version if we're on the lockscreen and this notification isn't
- // publicly visible.
- event.setParcelableData(notification.publicVersion);
- } else {
- event.setParcelableData(notification);
- }
- final CharSequence tickerText = notification.tickerText;
- if (!TextUtils.isEmpty(tickerText)) {
- event.getText().add(tickerText);
- }
-
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
-
/**
* Removes all NotificationsRecords with the same key as the given notification record
* from both lists. Do not call this method while iterating over either list.
@@ -10228,22 +9464,7 @@
}
}
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.clearEffectsLocked(canceledKey);
- } else {
- // sound
- if (canceledKey.equals(mSoundNotificationKey)) {
- clearSoundLocked();
- }
-
- // vibrate
- if (canceledKey.equals(mVibrateNotificationKey)) {
- clearVibrateLocked();
- }
-
- // light
- mLights.remove(canceledKey);
- }
+ mAttentionHelper.clearEffectsLocked(canceledKey);
}
// Record usage stats
@@ -10592,11 +9813,7 @@
cancellationElapsedTimeMs);
}
}
- if (Flags.refactorAttentionHelper()) {
- mAttentionHelper.updateLightsLocked();
- } else {
- updateLightsLocked();
- }
+ mAttentionHelper.updateLightsLocked();
}
}
@@ -10745,37 +9962,6 @@
}
@GuardedBy("mNotificationLock")
- void updateLightsLocked()
- {
- if (mNotificationLight == null) {
- return;
- }
-
- // handle notification lights
- NotificationRecord ledNotification = null;
- while (ledNotification == null && !mLights.isEmpty()) {
- final String owner = mLights.get(mLights.size() - 1);
- ledNotification = mNotificationsByKey.get(owner);
- if (ledNotification == null) {
- Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
- mLights.remove(owner);
- }
- }
-
- // Don't flash while we are in a call or screen is on
- if (ledNotification == null || isInCall() || mScreenOn) {
- mNotificationLight.turnOff();
- } else {
- NotificationRecord.Light light = ledNotification.getLight();
- if (light != null && mNotificationPulseEnabled) {
- // pulse repeatedly
- mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
- light.onMs, light.offMs);
- }
- }
- }
-
- @GuardedBy("mNotificationLock")
@NonNull
List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg,
String groupKey, int userId) {
@@ -10974,12 +10160,6 @@
}
}
- private void updateNotificationPulse() {
- synchronized (mNotificationLock) {
- updateLightsLocked();
- }
- }
-
protected boolean isCallingUidSystem() {
final int uid = Binder.getCallingUid();
return uid == Process.SYSTEM_UID;
@@ -11350,18 +10530,6 @@
}
}
- private boolean isInCall() {
- if (mInCallStateOffHook) {
- return true;
- }
- int audioMode = mAudioManager.getMode();
- if (audioMode == AudioManager.MODE_IN_CALL
- || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
- return true;
- }
- return false;
- }
-
public class NotificationAssistants extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 6ab4b99..7e58d0a 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static android.app.Flags.updateRankingTime;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -65,14 +66,12 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.widget.RemoteViews;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.uri.UriGrantsManagerInternal;
-
import dalvik.annotation.optimization.NeverCompile;
import java.io.PrintWriter;
@@ -1090,8 +1089,14 @@
private long calculateRankingTimeMs(long previousRankingTimeMs) {
Notification n = getNotification();
// Take developer provided 'when', unless it's in the future.
- if (n.when != 0 && n.when <= getSbn().getPostTime()) {
- return n.when;
+ if (updateRankingTime()) {
+ if (n.when != n.creationTime && n.when <= getSbn().getPostTime()){
+ return n.when;
+ }
+ } else {
+ if (n.when != 0 && n.when <= getSbn().getPostTime()) {
+ return n.when;
+ }
}
// If we've ranked a previous instance with a timestamp, inherit it. This case is
// important in order to have ranking stability for updating notifications.
@@ -1193,6 +1198,12 @@
return mPeopleOverride;
}
+ public void resetRankingTime() {
+ if (updateRankingTime()) {
+ mRankingTimeMs = calculateRankingTimeMs(getSbn().getPostTime());
+ }
+ }
+
public void setInterruptive(boolean interruptive) {
mIsInterruptive = interruptive;
final long now = System.currentTimeMillis();
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index ec98fff..e2f4d18 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -293,9 +293,26 @@
return START_PERMISSION_DENIED;
}
- Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
-
try {
+ boolean openAppDetailsIfOngoingUnarchival = getAppOpsManager().checkOp(
+ AppOpsManager.OP_UNARCHIVAL_CONFIRMATION, callingUid, callerPackageName)
+ == MODE_ALLOWED;
+ if (openAppDetailsIfOngoingUnarchival) {
+ PackageInstaller.SessionInfo activeUnarchivalSession = getActiveUnarchivalSession(
+ packageName, userId);
+ if (activeUnarchivalSession != null) {
+ mPm.mHandler.post(() -> {
+ Slog.i(TAG, "Opening app details page for ongoing unarchival of: "
+ + packageName);
+ getLauncherApps().startPackageInstallerSessionDetailsActivity(
+ activeUnarchivalSession, null, null);
+ });
+ return START_ABORTED;
+ }
+ }
+
+ Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
+
requestUnarchive(packageName, callerPackageName,
getOrCreateLauncherListener(userId, packageName),
UserHandle.of(userId),
@@ -793,8 +810,27 @@
}
}
- mPm.mHandler.post(
- () -> unarchiveInternal(packageName, userHandle, installerPackage, draftSessionId));
+ mPm.mHandler.post(() -> {
+ Slog.i(TAG, "Starting app unarchival for: " + packageName);
+ unarchiveInternal(packageName, userHandle, installerPackage,
+ draftSessionId);
+ });
+ }
+
+ @Nullable
+ private PackageInstaller.SessionInfo getActiveUnarchivalSession(String packageName,
+ int userId) {
+ List<PackageInstaller.SessionInfo> activeSessions =
+ mPm.mInstallerService.getAllSessions(userId).getList();
+ for (int idx = 0; idx < activeSessions.size(); idx++) {
+ PackageInstaller.SessionInfo activeSession = activeSessions.get(idx);
+ if (activeSession.appPackageName.equals(packageName)
+ && activeSession.userId == userId && activeSession.active
+ && activeSession.isUnarchival()) {
+ return activeSession;
+ }
+ }
+ return null;
}
private void requestUnarchiveConfirmation(String packageName, IntentSender statusReceiver,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 88e7596..f5ac830 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1717,20 +1717,26 @@
return false;
}
- if (android.multiuser.Flags.showSetScreenLockDialog()) {
- // Show the prompt to set a new screen lock if the device does not have one
- final KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
- if (km != null && !km.isDeviceSecure()) {
- Intent setScreenLockPromptIntent =
- SetScreenLockDialogActivity
- .createBaseIntent(LAUNCH_REASON_DISABLE_QUIET_MODE);
- setScreenLockPromptIntent.putExtra(EXTRA_ORIGIN_USER_ID, userId);
- mContext.startActivity(setScreenLockPromptIntent);
- return false;
- }
+ final KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
+ if (km != null && km.isDeviceSecure()) {
+ showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
+ return false;
+ } else if (km != null && !km.isDeviceSecure()
+ && android.multiuser.Flags.showSetScreenLockDialog()
+ // TODO(b/330720545): Add a better way to accomplish this, also use it
+ // to block profile creation w/o device credentials present.
+ && Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 1) {
+ Intent setScreenLockPromptIntent =
+ SetScreenLockDialogActivity
+ .createBaseIntent(LAUNCH_REASON_DISABLE_QUIET_MODE);
+ setScreenLockPromptIntent.putExtra(EXTRA_ORIGIN_USER_ID, userId);
+ mContext.startActivity(setScreenLockPromptIntent);
+ return false;
+ } else {
+ Slog.w(LOG_TAG, "Allowing profile unlock even when device credentials "
+ + "are not set for user " + userId);
}
- showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
- return false;
}
}
final boolean hasUnifiedChallenge =
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 18d2718..9b2ca39 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5786,7 +5786,7 @@
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
- if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) {
+ if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) {
ActivityRecord next = topRunningActivity(null, task.mTaskId);
if (next == null) {
next = topRunningActivity(null, INVALID_TASK_ID);
@@ -5830,6 +5830,15 @@
+ tr.mTaskId);
if (mTransitionController.isShellTransitionsEnabled()) {
+ // TODO(b/277838915): Consider to make it concurrent to eliminate the special case.
+ final Transition collecting = mTransitionController.getCollectingTransition();
+ if (collecting != null && collecting.mType == TRANSIT_OPEN) {
+ // It can be a CLOSING participate of an OPEN transition. This avoids the deferred
+ // transition from moving task to back after the task was moved to front.
+ collecting.collect(tr);
+ moveTaskToBackInner(tr, collecting);
+ return true;
+ }
final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */,
mTransitionController, mWmService.mSyncEngine);
// Guarantee that this gets its own transition by queueing on SyncEngine
@@ -5858,7 +5867,7 @@
return true;
}
- private boolean moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
+ private void moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
final Transition.ReadyCondition movedToBack =
new Transition.ReadyCondition("moved-to-back", task);
if (transition != null) {
@@ -5873,7 +5882,7 @@
if (inPinnedWindowingMode()) {
mTaskSupervisor.removeRootTask(this);
- return true;
+ return;
}
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
@@ -5896,7 +5905,6 @@
} else {
mRootWindowContainer.resumeFocusedTasksTopActivities();
}
- return true;
}
boolean willActivityBeVisible(IBinder token) {
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 1f54518..912ff4a 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -232,6 +232,9 @@
</xs:element>
<xs:element name="brightness" type="xs:float" maxOccurs="unbounded">
</xs:element>
+ <!-- Mapping of current lux to minimum allowed nits values. -->
+ <xs:element name="luxToMinimumNitsMap" type="nitsMap" maxOccurs="1">
+ </xs:element>
</xs:sequence>
<xs:attribute name="enabled" type="xs:boolean" use="optional"/>
</xs:complexType>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index c39c3d7..3c70890 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -255,9 +255,11 @@
method public java.util.List<java.lang.Float> getBacklight();
method public java.util.List<java.lang.Float> getBrightness();
method public boolean getEnabled();
+ method public com.android.server.display.config.NitsMap getLuxToMinimumNitsMap();
method public java.util.List<java.lang.Float> getNits();
method public java.math.BigDecimal getTransitionPoint();
method public void setEnabled(boolean);
+ method public void setLuxToMinimumNitsMap(com.android.server.display.config.NitsMap);
method public void setTransitionPoint(java.math.BigDecimal);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 73a2f65..5a022c0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -1651,6 +1651,17 @@
+ " <brightness>0.1</brightness>\n"
+ " <brightness>0.5</brightness>\n"
+ " <brightness>1.0</brightness>\n"
+ + " <luxToMinimumNitsMap>\n"
+ + " <point>\n"
+ + " <value>10</value> <nits>0.3</nits>\n"
+ + " </point>\n"
+ + " <point>\n"
+ + " <value>50</value> <nits>0.7</nits>\n"
+ + " </point>\n"
+ + " <point>\n"
+ + " <value>100</value> <nits>1.0</nits>\n"
+ + " </point>\n"
+ + " </luxToMinimumNitsMap>\n"
+ "</lowBrightness>";
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
index 5294943..5487bc5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
@@ -35,6 +35,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -280,7 +281,8 @@
@Override
List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
- Handler handler, BrightnessClamperController.ClamperChangeListener listener) {
+ Handler handler, BrightnessClamperController.ClamperChangeListener listener,
+ DisplayDeviceConfig displayDeviceConfig) {
return mModifiers;
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
index e4a7d98..749c400 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
@@ -15,13 +15,18 @@
*/
package com.android.server.display.brightness.clamper
-import android.os.PowerManager
import android.os.UserHandle
+import android.platform.test.annotations.RequiresFlagsEnabled
import android.provider.Settings
import android.testing.TestableContext
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED
+import com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
+import com.android.server.display.DisplayDeviceConfig
import com.android.server.display.brightness.BrightnessReason
+import com.android.server.display.feature.flags.Flags
import com.android.server.testutils.TestHandler
+import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -32,71 +37,197 @@
class BrightnessLowLuxModifierTest {
private var mockClamperChangeListener =
- mock<BrightnessClamperController.ClamperChangeListener>()
+ mock<BrightnessClamperController.ClamperChangeListener>()
val context = TestableContext(
- InstrumentationRegistry.getInstrumentation().getContext())
+ InstrumentationRegistry.getInstrumentation().getContext())
private val testHandler = TestHandler(null)
private lateinit var modifier: BrightnessLowLuxModifier
+ private var mockDisplayDeviceConfig = mock<DisplayDeviceConfig>()
+
+ private val LOW_LUX_BRIGHTNESS = 0.1f
+ private val TRANSITION_POINT = 0.25f
+ private val NORMAL_RANGE_BRIGHTNESS = 0.3f
+
@Before
fun setUp() {
- modifier = BrightnessLowLuxModifier(testHandler, mockClamperChangeListener, context)
+ modifier =
+ BrightnessLowLuxModifier(testHandler,
+ mockClamperChangeListener,
+ context,
+ mockDisplayDeviceConfig)
+
+ // values below transition point (even dimmer range)
+ // nits: 0.1 -> backlight 0.02 -> brightness -> 0.1
+ whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 1.0f))
+ .thenReturn(0.02f)
+ whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.02f))
+ .thenReturn(LOW_LUX_BRIGHTNESS)
+
+ // values above transition point (noraml range)
+ // nits: 10 -> backlight 0.2 -> brightness -> 0.3
+ whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 2f))
+ .thenReturn(0.15f)
+ whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.15f))
+ .thenReturn(0.24f)
+
+ // values above transition point (normal range)
+ // nits: 10 -> backlight 0.2 -> brightness -> 0.3
+ whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 10f))
+ .thenReturn(0.2f)
+ whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.2f))
+ .thenReturn(NORMAL_RANGE_BRIGHTNESS)
+
+ // min nits when lux of 400
+ whenever(mockDisplayDeviceConfig.getMinNitsFromLux(/* lux= */ 400f))
+ .thenReturn(1.0f)
+
+
+ whenever(mockDisplayDeviceConfig.lowBrightnessTransitionPoint).thenReturn(TRANSITION_POINT)
+
testHandler.flush()
}
@Test
- fun testThrottlingBounds() {
- Settings.Secure.putIntForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // true
- Settings.Secure.putFloatForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.7f, userId)
- modifier.recalculateLowerBound()
- testHandler.flush()
- assertThat(modifier.isActive).isTrue()
-
- // TODO: code currently returns MIN/MAX; update with lux values
- assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
- }
-
- @Test
- fun testGetReason_UserSet() {
- Settings.Secure.putIntForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
- Settings.Secure.putFloatForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_MIN_NITS, 30.0f, userId)
- modifier.recalculateLowerBound()
- testHandler.flush()
- assertThat(modifier.isActive).isTrue()
-
- // Test restriction from user setting
- assertThat(modifier.brightnessReason)
- .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
- }
-
- @Test
- fun testGetReason_Lux() {
- Settings.Secure.putIntForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
- Settings.Secure.putFloatForUser(context.contentResolver,
- Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.0f, userId)
- modifier.onAmbientLuxChange(3000.0f)
- testHandler.flush()
- assertThat(modifier.isActive).isTrue()
-
- // Test restriction from lux setting
- assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
- }
-
- @Test
fun testSettingOffDisablesModifier() {
+ // test transition point ensures brightness doesn't drop when setting is off.
Settings.Secure.putIntForUser(context.contentResolver,
Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId)
- assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.recalculateLowerBound()
+ testHandler.flush()
+ assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+ assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
modifier.onAmbientLuxChange(3000.0f)
testHandler.flush()
assertThat(modifier.isActive).isFalse()
- assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+ assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun testLuxRestrictsBrightnessRange() {
+ // test that high lux prevents low brightness range.
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
+ Settings.Secure.putFloatForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.1f, userId)
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.onAmbientLuxChange(400.0f)
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isTrue()
+ // Test restriction from lux setting
+ assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun testUserRestrictsBrightnessRange() {
+ // test that user minimum nits setting prevents low brightness range.
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
+ Settings.Secure.putFloatForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_MIN_NITS, 10.0f, userId)
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.recalculateLowerBound()
+ testHandler.flush()
+
+ // Test restriction from user setting
+ assertThat(modifier.isActive).isTrue()
+ assertThat(modifier.brightnessReason)
+ .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(NORMAL_RANGE_BRIGHTNESS)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun testOnToOff() {
+ // test that high lux prevents low brightness range.
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+ Settings.Secure.putFloatForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.onAmbientLuxChange(400.0f)
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isTrue()
+ // Test restriction from lux setting
+ assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId) // off
+
+ modifier.recalculateLowerBound()
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isFalse()
+ assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+ assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun testOffToOn() {
+ // test that high lux prevents low brightness range.
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId) // off
+ Settings.Secure.putFloatForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.onAmbientLuxChange(400.0f)
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isFalse()
+ assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+ assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+
+
+
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+ modifier.recalculateLowerBound()
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isTrue()
+ // Test restriction from lux setting
+ assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun testDisabledWhenAutobrightnessIsOff() {
+ // test that high lux prevents low brightness range.
+ Settings.Secure.putIntForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+ Settings.Secure.putFloatForUser(context.contentResolver,
+ Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+ modifier.onAmbientLuxChange(400.0f)
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isTrue()
+ // Test restriction from lux setting
+ assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+
+
+ modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_DISABLED)
+ modifier.onAmbientLuxChange(400.0f)
+ testHandler.flush()
+
+ assertThat(modifier.isActive).isFalse()
+ // Test restriction from lux setting
+ assertThat(modifier.brightnessReason).isEqualTo(0)
+ assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
}
}
+
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
deleted file mode 100644
index 517dcb4..0000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ /dev/null
@@ -1,1969 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.notification;
-
-import static android.app.Notification.FLAG_BUBBLE;
-import static android.app.Notification.GROUP_ALERT_ALL;
-import static android.app.Notification.GROUP_ALERT_CHILDREN;
-import static android.app.Notification.GROUP_ALERT_SUMMARY;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
-import static android.media.AudioAttributes.USAGE_NOTIFICATION;
-import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.Notification.Builder;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.graphics.drawable.Icon;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-import android.view.accessibility.IAccessibilityManagerClient;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.logging.InstanceIdSequence;
-import com.android.internal.logging.InstanceIdSequenceFake;
-import com.android.internal.util.IntPair;
-import com.android.server.UiServiceTestCase;
-import com.android.server.lights.LogicalLight;
-import com.android.server.pm.PackageManagerService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.verification.VerificationMode;
-
-import java.util.Objects;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
-public class BuzzBeepBlinkTest extends UiServiceTestCase {
-
- @Mock AudioManager mAudioManager;
- @Mock Vibrator mVibrator;
- @Mock android.media.IRingtonePlayer mRingtonePlayer;
- @Mock LogicalLight mLight;
- @Mock
- NotificationManagerService.WorkerHandler mHandler;
- @Mock
- NotificationUsageStats mUsageStats;
- @Mock
- IAccessibilityManager mAccessibilityService;
- @Mock
- KeyguardManager mKeyguardManager;
- NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
- private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
- 1 << 30);
-
- private NotificationManagerService mService;
- private String mPkg = "com.android.server.notification";
- private int mId = 1001;
- private int mOtherId = 1002;
- private String mTag = null;
- private int mUid = 1000;
- private int mPid = 2000;
- private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
- private NotificationChannel mChannel;
-
- private VibrateRepeatMatcher mVibrateOnceMatcher = new VibrateRepeatMatcher(-1);
- private VibrateRepeatMatcher mVibrateLoopMatcher = new VibrateRepeatMatcher(0);
-
- private static final long[] CUSTOM_VIBRATION = new long[] {
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
- private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
- private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
- .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
- .build();
- private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
- private static final int CUSTOM_LIGHT_ON = 10000;
- private static final int CUSTOM_LIGHT_OFF = 10000;
- private static final int MAX_VIBRATION_DELAY = 1000;
- private static final float DEFAULT_VOLUME = 1.0f;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- getContext().addMockSystemService(Vibrator.class, mVibrator);
-
- when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
- when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
- // consistent with focus not exclusive and volume not muted
- when(mAudioManager.shouldNotificationSoundPlay(any(AudioAttributes.class)))
- .thenReturn(true);
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
- when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
- when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
- when(mVibrator.hasFrequencyControl()).thenReturn(false);
- when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
-
- long serviceReturnValue = IntPair.of(
- AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
- AccessibilityEvent.TYPES_ALL_MASK);
- when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
- AccessibilityManager accessibilityManager =
- new AccessibilityManager(getContext(), Handler.getMain(), mAccessibilityService,
- 0, true);
- verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
- assertTrue(accessibilityManager.isEnabled());
-
- mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger,
- mNotificationInstanceIdSequence));
- mService.setVibratorHelper(new VibratorHelper(getContext()));
- mService.setAudioManager(mAudioManager);
- mService.setSystemReady(true);
- mService.setHandler(mHandler);
- mService.setLights(mLight);
- mService.setScreenOn(false);
- mService.setUsageStats(mUsageStats);
- mService.setAccessibilityManager(accessibilityManager);
- mService.setKeyguardManager(mKeyguardManager);
- mService.mScreenOn = false;
- mService.mInCallStateOffHook = false;
- mService.mNotificationPulseEnabled = true;
-
- mChannel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
- }
-
- //
- // Convenience functions for creating notification records
- //
-
- private NotificationRecord getNoisyOtherNotification() {
- return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
- true /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBeepyNotification() {
- return getNotificationRecord(mId, false /* insistent */, false /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBeepyOtherNotification() {
- return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBeepyOnceNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getQuietNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- false /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getQuietOtherNotification() {
- return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
- false /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getQuietOnceNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- false /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getInsistentBeepyNotification() {
- return getNotificationRecord(mId, true /* insistent */, false /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getInsistentBeepyOnceNotification() {
- return getNotificationRecord(mId, true /* insistent */, true /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getInsistentBeepyLeanbackNotification() {
- return getLeanbackNotificationRecord(mId, true /* insistent */, false /* once */,
- true /* noisy */, false /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBuzzyNotification() {
- return getNotificationRecord(mId, false /* insistent */, false /* once */,
- false /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBuzzyOtherNotification() {
- return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
- false /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBuzzyOnceNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- false /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getInsistentBuzzyNotification() {
- return getNotificationRecord(mId, true /* insistent */, false /* once */,
- false /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getBuzzyBeepyNotification() {
- return getNotificationRecord(mId, false /* insistent */, false /* once */,
- true /* noisy */, true /* buzzy*/, false /* lights */);
- }
-
- private NotificationRecord getLightsNotification() {
- return getNotificationRecord(mId, false /* insistent */, false /* once */,
- false /* noisy */, false /* buzzy*/, true /* lights */);
- }
-
- private NotificationRecord getLightsOnceNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- false /* noisy */, false /* buzzy*/, true /* lights */);
- }
-
- private NotificationRecord getCallRecord(int id, NotificationChannel channel, boolean looping) {
- final Builder builder = new Builder(getContext())
- .setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setPriority(Notification.PRIORITY_HIGH);
- Notification n = builder.build();
- if (looping) {
- n.flags |= Notification.FLAG_INSISTENT;
- }
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
- mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
- mService.addNotification(r);
-
- return r;
- }
-
- private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
- boolean noisy, boolean buzzy, boolean lights) {
- return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, buzzy, noisy,
- lights, null, Notification.GROUP_ALERT_ALL, false);
- }
-
- private NotificationRecord getLeanbackNotificationRecord(int id, boolean insistent,
- boolean once,
- boolean noisy, boolean buzzy, boolean lights) {
- return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true,
- true,
- null, Notification.GROUP_ALERT_ALL, true);
- }
-
- private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
- return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
- groupKey, groupAlertBehavior, false);
- }
-
- private NotificationRecord getLightsNotificationRecord(String groupKey,
- int groupAlertBehavior) {
- return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true,
- true, true, groupKey, groupAlertBehavior, false);
- }
-
- private NotificationRecord getNotificationRecord(int id,
- boolean insistent, boolean once,
- boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
- boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
- boolean isLeanback) {
-
- final Builder builder = new Builder(getContext())
- .setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setPriority(Notification.PRIORITY_HIGH)
- .setOnlyAlertOnce(once);
-
- int defaults = 0;
- if (noisy) {
- if (defaultSound) {
- defaults |= Notification.DEFAULT_SOUND;
- mChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
- Notification.AUDIO_ATTRIBUTES_DEFAULT);
- } else {
- builder.setSound(CUSTOM_SOUND);
- mChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
- }
- } else {
- mChannel.setSound(null, null);
- }
- if (buzzy) {
- if (defaultVibration) {
- defaults |= Notification.DEFAULT_VIBRATE;
- } else {
- builder.setVibrate(CUSTOM_VIBRATION);
- mChannel.setVibrationPattern(CUSTOM_VIBRATION);
- }
- mChannel.enableVibration(true);
- } else {
- mChannel.setVibrationPattern(null);
- mChannel.enableVibration(false);
- }
-
- if (lights) {
- if (defaultLights) {
- defaults |= Notification.DEFAULT_LIGHTS;
- } else {
- builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
- }
- mChannel.enableLights(true);
- } else {
- mChannel.enableLights(false);
- }
- builder.setDefaults(defaults);
-
- builder.setGroup(groupKey);
- builder.setGroupAlertBehavior(groupAlertBehavior);
-
- Notification n = builder.build();
- if (insistent) {
- n.flags |= Notification.FLAG_INSISTENT;
- }
-
- Context context = spy(getContext());
- PackageManager packageManager = spy(context.getPackageManager());
- when(context.getPackageManager()).thenReturn(packageManager);
- when(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
- .thenReturn(isLeanback);
-
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
- mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(context, sbn, mChannel);
- mService.addNotification(r);
- return r;
- }
-
- //
- // Convenience functions for interacting with mocks
- //
-
- private void verifyNeverBeep() throws RemoteException {
- verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any(), anyFloat());
- }
-
- private void verifyBeepUnlooped() throws RemoteException {
- verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any(),
- eq(DEFAULT_VOLUME));
- }
-
- private void verifyBeepLooped() throws RemoteException {
- verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any(),
- eq(DEFAULT_VOLUME));
- }
-
- private void verifyBeep(int times) throws RemoteException {
- verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any(),
- eq(DEFAULT_VOLUME));
- }
-
- private void verifyNeverStopAudio() throws RemoteException {
- verify(mRingtonePlayer, never()).stopAsync();
- }
-
- private void verifyStopAudio() throws RemoteException {
- verify(mRingtonePlayer, times(1)).stopAsync();
- }
-
- private void verifyNeverVibrate() {
- verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(),
- any(VibrationAttributes.class));
- }
-
- private void verifyVibrate() {
- verifyVibrate(/* times= */ 1);
- }
-
- private void verifyVibrate(int times) {
- verifyVibrate(mVibrateOnceMatcher, times(times));
- }
-
- private void verifyVibrateLooped() {
- verifyVibrate(mVibrateLoopMatcher, times(1));
- }
-
- private void verifyDelayedVibrateLooped() {
- verifyVibrate(mVibrateLoopMatcher, timeout(MAX_VIBRATION_DELAY).times(1));
- }
-
- private void verifyDelayedVibrate(VibrationEffect effect) {
- verifyVibrate(argument -> Objects.equals(effect, argument),
- timeout(MAX_VIBRATION_DELAY).times(1));
- }
-
- private void verifyDelayedNeverVibrate() {
- verify(mVibrator, after(MAX_VIBRATION_DELAY).never()).vibrate(anyInt(), anyString(), any(),
- anyString(), any(VibrationAttributes.class));
- }
-
- private void verifyVibrate(ArgumentMatcher<VibrationEffect> effectMatcher,
- VerificationMode verification) {
- ArgumentCaptor<VibrationAttributes> captor =
- ArgumentCaptor.forClass(VibrationAttributes.class);
- verify(mVibrator, verification).vibrate(eq(Process.SYSTEM_UID),
- eq(PackageManagerService.PLATFORM_PACKAGE_NAME), argThat(effectMatcher),
- anyString(), captor.capture());
- assertEquals(0, (captor.getValue().getFlags()
- & VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
- }
-
- private void verifyStopVibrate() {
- int alarmClassUsageFilter =
- VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK;
- verify(mVibrator, times(1)).cancel(eq(alarmClassUsageFilter));
- }
-
- private void verifyNeverStopVibrate() {
- verify(mVibrator, never()).cancel();
- verify(mVibrator, never()).cancel(anyInt());
- }
-
- private void verifyNeverLights() {
- verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
- }
-
- private void verifyLights() {
- verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
- }
-
- //
- // Tests
- //
-
- @Test
- public void testLights() throws Exception {
- NotificationRecord r = getLightsNotification();
- r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyLights();
- assertTrue(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testBeep() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepUnlooped();
- verifyNeverVibrate();
- verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLockedPrivateA11yRedaction() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
- r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
- when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
- AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
- when(accessibilityManager.isEnabled()).thenReturn(true);
- mService.setAccessibilityManager(accessibilityManager);
-
- mService.buzzBeepBlinkLocked(r);
-
- ArgumentCaptor<AccessibilityEvent> eventCaptor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
-
- verify(accessibilityManager, times(1))
- .sendAccessibilityEvent(eventCaptor.capture());
-
- AccessibilityEvent event = eventCaptor.getValue();
- assertEquals(r.getNotification().publicVersion, event.getParcelableData());
- }
-
- @Test
- public void testLockedOverridePrivateA11yRedaction() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
- r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
- when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
- AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
- when(accessibilityManager.isEnabled()).thenReturn(true);
- mService.setAccessibilityManager(accessibilityManager);
-
- mService.buzzBeepBlinkLocked(r);
-
- ArgumentCaptor<AccessibilityEvent> eventCaptor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
-
- verify(accessibilityManager, times(1))
- .sendAccessibilityEvent(eventCaptor.capture());
-
- AccessibilityEvent event = eventCaptor.getValue();
- assertEquals(r.getNotification().publicVersion, event.getParcelableData());
- }
-
- @Test
- public void testLockedPublicA11yNoRedaction() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
- r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
- when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
- AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
- when(accessibilityManager.isEnabled()).thenReturn(true);
- mService.setAccessibilityManager(accessibilityManager);
-
- mService.buzzBeepBlinkLocked(r);
-
- ArgumentCaptor<AccessibilityEvent> eventCaptor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
-
- verify(accessibilityManager, times(1))
- .sendAccessibilityEvent(eventCaptor.capture());
-
- AccessibilityEvent event = eventCaptor.getValue();
- assertEquals(r.getNotification(), event.getParcelableData());
- }
-
- @Test
- public void testUnlockedPrivateA11yNoRedaction() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
- r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
- when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
- AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
- when(accessibilityManager.isEnabled()).thenReturn(true);
- mService.setAccessibilityManager(accessibilityManager);
-
- mService.buzzBeepBlinkLocked(r);
-
- ArgumentCaptor<AccessibilityEvent> eventCaptor =
- ArgumentCaptor.forClass(AccessibilityEvent.class);
-
- verify(accessibilityManager, times(1))
- .sendAccessibilityEvent(eventCaptor.capture());
-
- AccessibilityEvent event = eventCaptor.getValue();
- assertEquals(r.getNotification(), event.getParcelableData());
- }
-
- @Test
- public void testBeepInsistently() throws Exception {
- NotificationRecord r = getInsistentBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepLooped();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoLeanbackBeep() throws Exception {
- NotificationRecord r = getInsistentBeepyLeanbackNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoBeepForAutomotiveIfEffectsDisabled() throws Exception {
- mService.setIsAutomotive(true);
- mService.setNotificationEffectsEnabledForAutomotive(false);
-
- NotificationRecord r = getBeepyNotification();
- r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- }
-
- @Test
- public void testNoBeepForImportanceDefaultInAutomotiveIfEffectsEnabled() throws Exception {
- mService.setIsAutomotive(true);
- mService.setNotificationEffectsEnabledForAutomotive(true);
-
- NotificationRecord r = getBeepyNotification();
- r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- }
-
- @Test
- public void testBeepForImportanceHighInAutomotiveIfEffectsEnabled() throws Exception {
- mService.setIsAutomotive(true);
- mService.setNotificationEffectsEnabledForAutomotive(true);
-
- NotificationRecord r = getBeepyNotification();
- r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepUnlooped();
- assertTrue(r.isInterruptive());
- }
-
- @Test
- public void testNoInterruptionForMin() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- verifyNeverVibrate();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoInterruptionForIntercepted() throws Exception {
- NotificationRecord r = getBeepyNotification();
- r.setIntercepted(true);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- verifyNeverVibrate();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testBeepTwice() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mRingtonePlayer);
-
- // update should beep
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
- verifyBeepUnlooped();
- verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testHonorAlertOnlyOnceForBeep() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getBeepyOnceNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mRingtonePlayer);
-
- // update should not beep
- mService.buzzBeepBlinkLocked(s);
- verifyNeverBeep();
- verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
- }
-
- @Test
- public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverStopAudio();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getBeepyOnceNotification();
- s.isUpdate = true;
-
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(s);
-
- verifyNeverStopAudio();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- /**
- * Tests the case where the user re-posts a {@link Notification} with looping sound where
- * {@link Notification.Builder#setOnlyAlertOnce(true)} has been called. This should silence
- * the sound associated with the notification.
- * @throws Exception
- */
- @Test
- public void testNoisyOnceUpdateDoesCancelAudio() throws Exception {
- NotificationRecord r = getInsistentBeepyNotification();
- NotificationRecord s = getInsistentBeepyOnceNotification();
- s.isUpdate = true;
-
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(s);
-
- verifyStopAudio();
- }
-
- @Test
- public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getQuietNotification();
- s.isUpdate = true;
- NotificationRecord other = getNoisyOtherNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(other); // this takes the audio stream
- Mockito.reset(mRingtonePlayer);
-
- // should not stop noise, since we no longer own it
- mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
- verifyNeverStopAudio();
- assertTrue(other.isInterruptive());
- assertNotEquals(-1, other.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietInterloperDoesNotCancelAudio() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord other = getQuietOtherNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mRingtonePlayer);
-
- // should not stop noise, since it does not own it
- mService.buzzBeepBlinkLocked(other);
- verifyNeverStopAudio();
- }
-
- @Test
- public void testQuietUpdateCancelsAudio() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getQuietNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- Mockito.reset(mRingtonePlayer);
-
- // quiet update should stop making noise
- mService.buzzBeepBlinkLocked(s);
- verifyStopAudio();
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietOnceUpdateCancelsAudio() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getQuietOnceNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- Mockito.reset(mRingtonePlayer);
-
- // stop making noise - this is a weird corner case, but quiet should override once
- mService.buzzBeepBlinkLocked(s);
- verifyStopAudio();
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testInCallNotification() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mRingtonePlayer);
-
- mService.mInCallStateOffHook = true;
- mService.buzzBeepBlinkLocked(r);
-
- verify(mService, times(1)).playInCallNotification();
- verifyNeverBeep(); // doesn't play normal beep
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception {
- NotificationRecord r = getBuzzyBeepyNotification();
- assertTrue(r.getSound() != null);
-
- // the phone is quiet
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyDelayedVibrate(r.getVibration());
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoDemoteSoundToVibrateIfNonNotificationStream() throws Exception {
- NotificationRecord r = getBeepyNotification();
- assertTrue(r.getSound() != null);
- assertNull(r.getVibration());
-
- // the phone is quiet
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
- // all streams at 1 means no muting from audio framework
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(true);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverVibrate();
- verifyBeepUnlooped();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testDemoteSoundToVibrate() throws Exception {
- NotificationRecord r = getBeepyNotification();
- assertTrue(r.getSound() != null);
- assertNull(r.getVibration());
-
- // the phone is quiet
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyDelayedVibrate(
- mService.getVibratorHelper().createFallbackVibration(/* insistent= */ false));
- verify(mRingtonePlayer, never()).playAsync
- (anyObject(), anyObject(), anyBoolean(), anyObject(), anyFloat());
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testDemoteInsistentSoundToVibrate() throws Exception {
- NotificationRecord r = getInsistentBeepyNotification();
- assertTrue(r.getSound() != null);
- assertNull(r.getVibration());
-
- // the phone is quiet
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyDelayedVibrateLooped();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testVibrate() throws Exception {
- NotificationRecord r = getBuzzyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- verifyVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testInsistentVibrate() {
- NotificationRecord r = getInsistentBuzzyNotification();
-
- mService.buzzBeepBlinkLocked(r);
- verifyVibrateLooped();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testVibrateTwice() {
- NotificationRecord r = getBuzzyNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mVibrator);
-
- // update should vibrate
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
- verifyVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testPostSilently() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- r.setPostSilently(true);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummarySilenceChild() throws Exception {
- NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
-
- mService.buzzBeepBlinkLocked(child);
-
- verifyNeverBeep();
- assertFalse(child.isInterruptive());
- assertEquals(-1, child.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummaryNoSilenceSummary() throws Exception {
- NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
-
- verifyBeepUnlooped();
- // summaries are never interruptive for notification counts
- assertFalse(summary.isInterruptive());
- assertNotEquals(-1, summary.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummaryNoSilenceNonGroupChild() throws Exception {
- NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_SUMMARY);
-
- mService.buzzBeepBlinkLocked(nonGroup);
-
- verifyBeepUnlooped();
- assertTrue(nonGroup.isInterruptive());
- assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildSilenceSummary() throws Exception {
- NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
-
- verifyNeverBeep();
- assertFalse(summary.isInterruptive());
- assertEquals(-1, summary.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildNoSilenceChild() throws Exception {
- NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
-
- mService.buzzBeepBlinkLocked(child);
-
- verifyBeepUnlooped();
- assertTrue(child.isInterruptive());
- assertNotEquals(-1, child.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildNoSilenceNonGroupSummary() throws Exception {
- NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_CHILDREN);
-
- mService.buzzBeepBlinkLocked(nonGroup);
-
- verifyBeepUnlooped();
- assertTrue(nonGroup.isInterruptive());
- assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertAllNoSilenceGroup() throws Exception {
- NotificationRecord group = getBeepyNotificationRecord("a", GROUP_ALERT_ALL);
-
- mService.buzzBeepBlinkLocked(group);
-
- verifyBeepUnlooped();
- assertTrue(group.isInterruptive());
- assertNotEquals(-1, group.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testHonorAlertOnlyOnceForBuzz() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord s = getBuzzyOnceNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mVibrator);
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-
- // update should not beep
- mService.buzzBeepBlinkLocked(s);
- verifyNeverVibrate();
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
- NotificationRecord r = getBuzzyNotification();
-
- mService.buzzBeepBlinkLocked(r);
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord s = getBuzzyOnceNotification();
- s.isUpdate = true;
-
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(s);
-
- verifyNeverStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord s = getQuietNotification();
- s.isUpdate = true;
- NotificationRecord other = getNoisyOtherNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
- Mockito.reset(mVibrator);
-
- // should not stop vibrate, since we no longer own it
- mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
- verifyNeverStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertTrue(other.isInterruptive());
- assertNotEquals(-1, other.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord other = getQuietOtherNotification();
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- Mockito.reset(mVibrator);
-
- // should not stop noise, since it does not own it
- mService.buzzBeepBlinkLocked(other);
- verifyNeverStopVibrate();
- assertFalse(other.isInterruptive());
- assertEquals(-1, other.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietUpdateCancelsVibrate() {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord s = getQuietNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- verifyVibrate();
-
- // quiet update should stop making noise
- mService.buzzBeepBlinkLocked(s);
- verifyStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietOnceUpdateCancelVibrate() throws Exception {
- NotificationRecord r = getBuzzyNotification();
- NotificationRecord s = getQuietOnceNotification();
- s.isUpdate = true;
-
- // set up internal state
- mService.buzzBeepBlinkLocked(r);
- verifyVibrate();
-
- // stop making noise - this is a weird corner case, but quiet should override once
- mService.buzzBeepBlinkLocked(s);
- verifyStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
- NotificationRecord r = getBeepyNotification();
- NotificationRecord s = getQuietNotification();
-
- // the phone is quiet
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
- mService.buzzBeepBlinkLocked(r);
- verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false));
-
- // quiet update should stop making noise
- mService.buzzBeepBlinkLocked(s);
- verifyStopVibrate();
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- assertFalse(s.isInterruptive());
- assertEquals(-1, s.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testEmptyUriSoundTreatedAsNoSound() throws Exception {
- NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
- channel.setSound(Uri.EMPTY, null);
- final Notification n = new Builder(getContext(), "test")
- .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
- mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
- mService.addNotification(r);
-
- mService.buzzBeepBlinkLocked(r);
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testRepeatedSoundOverLimitMuted() throws Exception {
- when(mUsageStats.isAlertRateLimited(any())).thenReturn(true);
-
- NotificationRecord r = getBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testPostingSilentNotificationDoesNotAffectRateLimiting() throws Exception {
- NotificationRecord r = getQuietNotification();
- mService.buzzBeepBlinkLocked(r);
-
- verify(mUsageStats, never()).isAlertRateLimited(any());
- }
-
- @Test
- public void testPostingGroupSuppressedDoesNotAffectRateLimiting() throws Exception {
- NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
- verify(mUsageStats, never()).isAlertRateLimited(any());
- }
-
- @Test
- public void testGroupSuppressionFailureDoesNotAffectRateLimiting() {
- NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
- verify(mUsageStats, times(1)).isAlertRateLimited(any());
- }
-
- @Test
- public void testCrossUserSoundMuted() throws Exception {
- final Notification n = new Builder(getContext(), "test")
- .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-
- int userId = mUser.getIdentifier() + 1;
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
- mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn,
- new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
- mService.buzzBeepBlinkLocked(r);
- verifyNeverBeep();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testA11yMinInitialPost() throws Exception {
- NotificationRecord r = getQuietNotification();
- r.setSystemImportance(IMPORTANCE_MIN);
- mService.buzzBeepBlinkLocked(r);
- verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
- }
-
- @Test
- public void testA11yQuietInitialPost() throws Exception {
- NotificationRecord r = getQuietNotification();
- mService.buzzBeepBlinkLocked(r);
- verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
- }
-
- @Test
- public void testA11yQuietUpdate() throws Exception {
- NotificationRecord r = getQuietNotification();
- mService.buzzBeepBlinkLocked(r);
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
- verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
- }
-
- @Test
- public void testA11yCrossUserEventNotSent() throws Exception {
- final Notification n = new Builder(getContext(), "test")
- .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
- int userId = mUser.getIdentifier() + 1;
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
- mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn,
- new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
- mService.buzzBeepBlinkLocked(r);
-
- verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
- }
-
- @Test
- public void testLightsScreenOn() {
- mService.mScreenOn = true;
- NotificationRecord r = getLightsNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertTrue(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsInCall() {
- mService.mInCallStateOffHook = true;
- NotificationRecord r = getLightsNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsSilentUpdate() {
- NotificationRecord r = getLightsOnceNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyLights();
- assertTrue(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
-
- r = getLightsOnceNotification();
- r.isUpdate = true;
- mService.buzzBeepBlinkLocked(r);
- // checks that lights happened once, i.e. this new call didn't trigger them again
- verifyLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsUnimportant() {
- NotificationRecord r = getLightsNotification();
- r.setSystemImportance(IMPORTANCE_LOW);
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsNoLights() {
- NotificationRecord r = getQuietNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsNoLightOnDevice() {
- mService.mHasLight = false;
- NotificationRecord r = getLightsNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsLightsOffGlobally() {
- mService.mNotificationPulseEnabled = false;
- NotificationRecord r = getLightsNotification();
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsDndIntercepted() {
- NotificationRecord r = getLightsNotification();
- r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummaryNoLightsChild() {
- NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
-
- mService.buzzBeepBlinkLocked(child);
-
- verifyNeverLights();
- assertFalse(child.isInterruptive());
- assertEquals(-1, child.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummaryLightsSummary() {
- NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
-
- verifyLights();
- // summaries should never count for interruptiveness counts
- assertFalse(summary.isInterruptive());
- assertEquals(-1, summary.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertSummaryLightsNonGroupChild() {
- NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY);
-
- mService.buzzBeepBlinkLocked(nonGroup);
-
- verifyLights();
- assertTrue(nonGroup.isInterruptive());
- assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildNoLightsSummary() {
- NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
- summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
- mService.buzzBeepBlinkLocked(summary);
-
- verifyNeverLights();
- assertFalse(summary.isInterruptive());
- assertEquals(-1, summary.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildLightsChild() {
- NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
-
- mService.buzzBeepBlinkLocked(child);
-
- verifyLights();
- assertTrue(child.isInterruptive());
- assertEquals(-1, child.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertChildLightsNonGroupSummary() {
- NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN);
-
- mService.buzzBeepBlinkLocked(nonGroup);
-
- verifyLights();
- assertTrue(nonGroup.isInterruptive());
- assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testGroupAlertAllLightsGroup() {
- NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL);
-
- mService.buzzBeepBlinkLocked(group);
-
- verifyLights();
- assertTrue(group.isInterruptive());
- assertEquals(-1, group.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testLightsCheckCurrentUser() {
- final Notification n = new Builder(getContext(), "test")
- .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
- int userId = mUser.getIdentifier() + 10;
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
- mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn,
- new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
- mService.buzzBeepBlinkLocked(r);
- verifyNeverLights();
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testListenerHintCall() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
-
- mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- }
-
- @Test
- public void testListenerHintCall_notificationSound() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepUnlooped();
- }
-
- @Test
- public void testListenerHintNotification() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- }
-
- @Test
- public void testListenerHintBoth() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
- NotificationRecord s = getBeepyNotification();
-
- mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
- | NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
- mService.buzzBeepBlinkLocked(r);
- mService.buzzBeepBlinkLocked(s);
-
- verifyNeverBeep();
- }
-
- @Test
- public void testListenerHintNotification_callSound() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
-
- mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepLooped();
- }
-
- @Test
- public void testCannotInterruptRingtoneInsistentBeep() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
- mService.addNotification(ringtoneNotification);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
-
- NotificationRecord interrupter = getBeepyOtherNotification();
- assertTrue(mService.shouldMuteNotificationLocked(interrupter));
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyBeep(1);
-
- assertFalse(interrupter.isInterruptive());
- assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testRingtoneInsistentBeep_canUpdate() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
- mService.addNotification(ringtoneNotification);
- assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
- verifyDelayedVibrateLooped();
- Mockito.reset(mVibrator);
- Mockito.reset(mRingtonePlayer);
-
- assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
- mService.buzzBeepBlinkLocked(ringtoneNotification);
-
- // beep wasn't reset
- verifyNeverBeep();
- verifyNeverVibrate();
- verifyNeverStopAudio();
- verifyNeverStopVibrate();
- }
-
- @Test
- public void testRingtoneInsistentBeep_clearEffectsStopsSoundAndVibration() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
- mService.addNotification(ringtoneNotification);
- assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
- verifyDelayedVibrateLooped();
-
- mService.clearSoundLocked();
- mService.clearVibrateLocked();
-
- verifyStopAudio();
- verifyStopVibrate();
- }
-
- @Test
- public void testRingtoneInsistentBeep_neverVibratesWhenEffectsClearedBeforeDelay()
- throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
- mService.addNotification(ringtoneNotification);
- assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
- verifyNeverVibrate();
-
- mService.clearSoundLocked();
- mService.clearVibrateLocked();
-
- verifyStopAudio();
- verifyDelayedNeverVibrate();
- }
-
- @Test
- public void testCannotInterruptRingtoneInsistentBuzz() {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Uri.EMPTY,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
- assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyVibrateLooped();
-
- NotificationRecord interrupter = getBuzzyOtherNotification();
- assertTrue(mService.shouldMuteNotificationLocked(interrupter));
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyVibrate(1);
-
- assertFalse(interrupter.isInterruptive());
- assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testCanInterruptRingtoneNonInsistentBeep() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepUnlooped();
-
- NotificationRecord interrupter = getBeepyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyBeep(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testCanInterruptRingtoneNonInsistentBuzz() {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(null,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyVibrate();
-
- NotificationRecord interrupter = getBuzzyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyVibrate(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testRingtoneInsistentBeep_doesNotBlockFutureSoundsOnceStopped() throws Exception {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
-
- mService.clearSoundLocked();
-
- NotificationRecord interrupter = getBeepyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyBeep(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testRingtoneInsistentBuzz_doesNotBlockFutureSoundsOnceStopped() {
- NotificationChannel ringtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- ringtoneChannel.setSound(null,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
- ringtoneChannel.enableVibration(true);
- NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyVibrateLooped();
-
- mService.clearVibrateLocked();
-
- NotificationRecord interrupter = getBuzzyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyVibrate(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testCanInterruptNonRingtoneInsistentBeep() throws Exception {
- NotificationChannel fakeRingtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
- verifyBeepLooped();
-
- NotificationRecord interrupter = getBeepyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyBeep(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testCanInterruptNonRingtoneInsistentBuzz() {
- NotificationChannel fakeRingtoneChannel =
- new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
- fakeRingtoneChannel.enableVibration(true);
- fakeRingtoneChannel.setSound(null,
- new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION).build());
- NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
-
- mService.buzzBeepBlinkLocked(ringtoneNotification);
-
- NotificationRecord interrupter = getBuzzyOtherNotification();
- mService.buzzBeepBlinkLocked(interrupter);
-
- verifyVibrate(2);
-
- assertTrue(interrupter.isInterruptive());
- }
-
- @Test
- public void testBubbleSuppressedNotificationDoesntMakeSound() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
- mock(PendingIntent.class), mock(Icon.class))
- .build();
-
- NotificationRecord record = getBuzzyNotification();
- metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
- record.getNotification().setBubbleMetadata(metadata);
- record.setAllowBubble(true);
- record.getNotification().flags |= FLAG_BUBBLE;
- record.isUpdate = true;
- record.setInterruptive(false);
-
- mService.buzzBeepBlinkLocked(record);
- verifyNeverVibrate();
- }
-
- @Test
- public void testOverflowBubbleSuppressedNotificationDoesntMakeSound() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
- mock(PendingIntent.class), mock(Icon.class))
- .build();
-
- NotificationRecord record = getBuzzyNotification();
- metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
- record.getNotification().setBubbleMetadata(metadata);
- record.setFlagBubbleRemoved(true);
- record.setAllowBubble(true);
- record.isUpdate = true;
- record.setInterruptive(false);
-
- mService.buzzBeepBlinkLocked(record);
- verifyNeverVibrate();
- }
-
- @Test
- public void testBubbleUpdateMakesSound() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
- mock(PendingIntent.class), mock(Icon.class))
- .build();
-
- NotificationRecord record = getBuzzyNotification();
- record.getNotification().setBubbleMetadata(metadata);
- record.setAllowBubble(true);
- record.getNotification().flags |= FLAG_BUBBLE;
- record.isUpdate = true;
- record.setInterruptive(true);
-
- mService.buzzBeepBlinkLocked(record);
- verifyVibrate(1);
- }
-
- @Test
- public void testNewBubbleSuppressedNotifMakesSound() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
- mock(PendingIntent.class), mock(Icon.class))
- .build();
-
- NotificationRecord record = getBuzzyNotification();
- metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
- record.getNotification().setBubbleMetadata(metadata);
- record.setAllowBubble(true);
- record.getNotification().flags |= FLAG_BUBBLE;
- record.isUpdate = false;
- record.setInterruptive(true);
-
- mService.buzzBeepBlinkLocked(record);
- verifyVibrate(1);
- }
-
- @Test
- public void testStartFlashNotificationEvent_receiveBeepyNotification() throws Exception {
- NotificationRecord r = getBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepUnlooped();
- verifyNeverVibrate();
- verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
- eq(r.getSbn().getPackageName()));
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testStartFlashNotificationEvent_receiveBuzzyNotification() throws Exception {
- NotificationRecord r = getBuzzyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- verifyVibrate();
- verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
- eq(r.getSbn().getPackageName()));
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testStartFlashNotificationEvent_receiveBuzzyBeepyNotification() throws Exception {
- NotificationRecord r = getBuzzyBeepyNotification();
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyBeepUnlooped();
- verifyDelayedVibrate(r.getVibration());
- verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
- eq(r.getSbn().getPackageName()));
- assertTrue(r.isInterruptive());
- assertNotEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- @Test
- public void testStartFlashNotificationEvent_receiveBuzzyBeepyNotification_ringerModeSilent()
- throws Exception {
- NotificationRecord r = getBuzzyBeepyNotification();
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
- when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
- mService.buzzBeepBlinkLocked(r);
-
- verifyNeverBeep();
- verifyNeverVibrate();
- verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
- eq(r.getSbn().getPackageName()));
- assertFalse(r.isInterruptive());
- assertEquals(-1, r.getLastAudiblyAlertedMs());
- }
-
- static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
- private final int mRepeatIndex;
-
- VibrateRepeatMatcher(int repeatIndex) {
- mRepeatIndex = repeatIndex;
- }
-
- @Override
- public boolean matches(VibrationEffect actual) {
- if (actual instanceof VibrationEffect.Composed
- && ((VibrationEffect.Composed) actual).getRepeatIndex() == mRepeatIndex) {
- return true;
- }
- // All non-waveform effects are essentially one shots.
- return mRepeatIndex == -1;
- }
-
- @Override
- public String toString() {
- return "repeatIndex=" + mRepeatIndex;
- }
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index a1c24f1..acac63c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -210,7 +210,6 @@
assertTrue(mAccessibilityManager.isEnabled());
// TODO (b/291907312): remove feature flag
- mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
// Disable feature flags by default. Tests should enable as needed.
mSetFlagsRule.disableFlags(Flags.FLAG_POLITE_NOTIFICATIONS,
Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS, Flags.FLAG_VIBRATE_WHILE_UNLOCKED);
@@ -2486,6 +2485,17 @@
}
}
+ @Test
+ public void testSoundResetsRankingTime() throws Exception {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_UPDATE_RANKING_TIME);
+ TestableFlagResolver flagResolver = new TestableFlagResolver();
+ initAttentionHelper(flagResolver);
+
+ NotificationRecord r = getBuzzyBeepyNotification();
+ mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+ assertThat(r.getRankingTimeMs()).isEqualTo(r.getSbn().getPostTime());
+ }
+
static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
private final int mRepeatIndex;
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 06a4ac9..4f7be46 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
+import static android.app.Flags.FLAG_UPDATE_RANKING_TIME;
import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.EXTRA_PICTURE;
import static android.app.Notification.EXTRA_PICTURE_ICON;
@@ -101,7 +102,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
@@ -111,11 +111,11 @@
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
-
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -124,7 +124,6 @@
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
-
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.isNull;
@@ -132,27 +131,7 @@
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
+import static org.mockito.Mockito.*;
import android.Manifest;
import android.annotation.Nullable;
@@ -207,7 +186,6 @@
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.media.AudioManager;
-import android.media.IRingtonePlayer;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Binder;
@@ -246,7 +224,6 @@
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;
import android.telecom.TelecomManager;
-import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -260,10 +237,8 @@
import android.util.Pair;
import android.util.Xml;
import android.widget.RemoteViews;
-
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.config.sysui.TestableFlagResolver;
@@ -294,13 +269,10 @@
import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
-
import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
-
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -439,6 +411,8 @@
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
+ NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+
private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
@@ -494,6 +468,9 @@
@Mock
StatusBarManagerInternal mStatusBar;
+ @Mock
+ NotificationAttentionHelper mAttentionHelper;
+
private NotificationManagerService.WorkerHandler mWorkerHandler;
private class TestableToastCallback extends ITransientNotification.Stub {
@@ -661,7 +638,7 @@
// TODO (b/291907312): remove feature flag
// NOTE: Prefer using the @EnableFlag annotation where possible. Do not add any android.app
// flags here.
- mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
+ mSetFlagsRule.disableFlags(
Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
initNMS();
@@ -695,11 +672,12 @@
mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal,
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
- mock(TelephonyManager.class),
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
mPowerManager, mPostNotificationTrackerFactory);
+ mService.setAttentionHelper(mAttentionHelper);
+
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
@@ -715,13 +693,6 @@
verify(mHistoryManager).onBootPhaseAppsCanStart();
}
- // TODO b/291907312: remove feature flag
- if (Flags.refactorAttentionHelper()) {
- mService.mAttentionHelper.setAudioManager(mAudioManager);
- } else {
- mService.setAudioManager(mAudioManager);
- }
-
mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
mService.setStrongAuthTracker(mStrongAuthTracker);
@@ -793,14 +764,16 @@
mBinderService = mService.getBinderService();
mInternalService = mService.getInternalService();
- mBinderService.createNotificationChannels(
- PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- mBinderService.createNotificationChannels(
- PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- mBinderService.createNotificationChannels(
- PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+ mBinderService.createNotificationChannels(PKG, new ParceledListSlice(
+ Arrays.asList(mTestNotificationChannel, mSilentChannel)));
+ mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice(
+ Arrays.asList(mTestNotificationChannel, mSilentChannel)));
+ mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
+ Arrays.asList(mTestNotificationChannel, mSilentChannel)));
assertNotNull(mBinderService.getNotificationChannel(
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
+ assertNotNull(mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, mSilentChannel.getId()));
clearInvocations(mRankingHandler);
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
@@ -1041,11 +1014,16 @@
private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
int userId) {
+ return generateNotificationRecord(channel, id, userId, "foo");
+ }
+
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
+ int userId, String title) {
if (channel == null) {
channel = mTestNotificationChannel;
}
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
- .setContentTitle("foo")
+ .setContentTitle(title)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0,
nb.build(), new UserHandle(userId), null, 0);
@@ -1811,23 +1789,6 @@
}
@Test
- public void testEnqueueNotificationWithTag_WritesExpectedLogs_NAHRefactor() throws Exception {
- // TODO b/291907312: remove feature flag
- mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
- // Cleanup NMS before re-initializing
- if (mService != null) {
- try {
- mService.onDestroy();
- } catch (IllegalStateException | IllegalArgumentException e) {
- // can throw if a broadcast receiver was never registered
- }
- }
- initNMS();
-
- testEnqueueNotificationWithTag_WritesExpectedLogs();
- }
-
- @Test
public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception {
final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates";
Notification original = new Notification.Builder(mContext,
@@ -10105,13 +10066,6 @@
@Test
public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
throws RemoteException {
- IRingtonePlayer mockPlayer = mock(IRingtonePlayer.class);
- when(mAudioManager.getRingtonePlayer()).thenReturn(mockPlayer);
- // Set up volume to be above 0, and for AudioManager to signal playback should happen,
- // for the sound to actually play
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
- when(mAudioManager.shouldNotificationSoundPlay(any(android.media.AudioAttributes.class)))
- .thenReturn(true);
setUpPrefsForBubbles(PKG, mUid,
true /* global */,
@@ -10130,25 +10084,7 @@
waitForIdle();
// Check audio is stopped
- verify(mockPlayer).stopAsync();
- }
-
- @Test
- public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped_NAHRefactor()
- throws Exception {
- // TODO b/291907312: remove feature flag
- mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
- // Cleanup NMS before re-initializing
- if (mService != null) {
- try {
- mService.onDestroy();
- } catch (IllegalStateException | IllegalArgumentException e) {
- // can throw if a broadcast receiver was never registered
- }
- }
- initNMS();
-
- testOnBubbleMetadataChangedToSuppressNotification_soundStopped();
+ verify(mAttentionHelper).clearEffectsLocked(nr.getKey());
}
@Test
@@ -14775,6 +14711,110 @@
verify(listener, never()).onCallNotificationRemoved(anyString(), any());
}
+ @Test
+ @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+ public void rankingTime_newNotification_noisy_matchesSbn() throws Exception {
+ NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ NotificationRecord posted = mService.mNotificationList.get(0);
+ long originalPostTime = posted.getSbn().getPostTime();
+ assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+ }
+
+ @Test
+ @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+ public void rankingTime_newNotification_silent_matchesSbn() throws Exception {
+ NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+ NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ NotificationRecord posted = mService.mNotificationList.get(0);
+ long originalPostTime = posted.getSbn().getPostTime();
+ assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+ }
+
+ @Test
+ @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+ public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception {
+ NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+ NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.mNotificationList.get(0);
+ long originalPostTime = posted.getSbn().getPostTime();
+ assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ assertThat(mService.mNotificationList.get(0).getRankingTimeMs())
+ .isEqualTo(originalPostTime);
+ }
+
+ @Test
+ @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+ public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception {
+ NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+ NotificationRecord nr = generateNotificationRecord(low, 0, mUserId);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.mNotificationList.get(0);
+ long originalPostTime = posted.getSbn().getPostTime();
+ assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+ NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar");
+ // no attention helper mocked behavior needed because this does not make noise
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
+ nrUpdate.getSbn().getUserId());
+ waitForIdle();
+
+ posted = mService.mNotificationList.get(0);
+ assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
+ assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
+ }
+
+ @Test
+ @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+ public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception {
+ NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+ NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.mNotificationList.get(0);
+ long originalPostTime = posted.getSbn().getPostTime();
+ assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+ NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId);
+ when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ ((NotificationRecord) args[0]).resetRankingTime();
+ return 2; // beep
+ }
+ });
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
+ nrUpdate.getSbn().getUserId());
+ waitForIdle();
+ posted = mService.mNotificationList.get(0);
+ assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
+ assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
+ }
+
private NotificationRecord createAndPostCallStyleNotification(String packageName,
UserHandle userHandle, String testName) throws Exception {
Person person = new Person.Builder().setName("caller").build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 70910b1..c1bb3e7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -164,7 +164,7 @@
mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
mock(UriGrantsManagerInternal.class),
mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
- mock(StatsManager.class), mock(TelephonyManager.class),
+ mock(StatsManager.class),
mock(ActivityManagerInternal.class),
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
mock(UsageStatsManagerInternal.class), mock(TelecomManager.class),
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 0b76154..19ce217 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -251,9 +251,9 @@
VibrationEffect effect = VibrationEffect.createWaveform(
new long[]{5, 5, 5}, new int[]{1, 1, 1}, -1);
- CompletableFuture<Void> mRequestVibrationParamsFuture = CompletableFuture.runAsync(() -> {
- mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.5f);
- });
+ mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.5f);
+ CompletableFuture<Void> mRequestVibrationParamsFuture = CompletableFuture.completedFuture(
+ null);
long vibrationId = startThreadAndDispatcher(effect, mRequestVibrationParamsFuture,
USAGE_RINGTONE);
waitForCompletion();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 5861d88..185677f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1589,7 +1589,8 @@
assertEquals(1f, ((PrimitiveSegment) segments.get(2)).getScale(), 1e-5);
verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 0.7f);
verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 0.4f);
- verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 1f);
+ verify(mVibratorFrameworkStatsLoggerMock,
+ timeout(TEST_TIMEOUT_MILLIS)).logVibrationAdaptiveHapticScale(UID, 1f);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ff7129c..0186006 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -64,8 +64,10 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
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;
@@ -2368,9 +2370,7 @@
assertTrue(transitA.isCollecting());
// finish collecting A
- transitA.start();
- transitA.setAllReady();
- mSyncEngine.tryFinishForTest(transitA.getSyncId());
+ tryFinishTransitionSyncSet(transitA);
waitUntilHandlersIdle();
assertTrue(transitA.isPlaying());
@@ -2476,6 +2476,36 @@
}
@Test
+ public void testDeferredMoveTaskToBack() {
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task task = activity.getTask();
+ registerTestTransitionPlayer();
+ final TransitionController controller = mWm.mRoot.mTransitionController;
+ mSyncEngine = createTestBLASTSyncEngine();
+ controller.setSyncEngine(mSyncEngine);
+ final Transition transition = createTestTransition(TRANSIT_CHANGE, controller);
+ controller.moveToCollecting(transition);
+ task.moveTaskToBack(task);
+ // Actual action will be deferred by current transition.
+ verify(task, never()).moveToBack(any(), any());
+
+ tryFinishTransitionSyncSet(transition);
+ waitUntilHandlersIdle();
+ // Continue to move task to back after the transition is done.
+ verify(task).moveToBack(any(), any());
+ final Transition moveBackTransition = controller.getCollectingTransition();
+ assertNotNull(moveBackTransition);
+ moveBackTransition.abort();
+
+ // The move-to-back can be collected in to a collecting OPEN transition.
+ clearInvocations(task);
+ final Transition transition2 = createTestTransition(TRANSIT_OPEN, controller);
+ controller.moveToCollecting(transition2);
+ task.moveTaskToBack(task);
+ verify(task).moveToBack(any(), any());
+ }
+
+ @Test
public void testNoSyncFlagIfOneTrack() {
final TransitionController controller = mAtm.getTransitionController();
final TestTransitionPlayer player = registerTestTransitionPlayer();
@@ -2492,17 +2522,11 @@
controller.startCollectOrQueue(transitC, (deferred) -> {});
// Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
- transitA.start();
- transitA.setAllReady();
- mSyncEngine.tryFinishForTest(transitA.getSyncId());
+ tryFinishTransitionSyncSet(transitA);
assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
- transitB.start();
- transitB.setAllReady();
- mSyncEngine.tryFinishForTest(transitB.getSyncId());
+ tryFinishTransitionSyncSet(transitB);
assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
- transitC.start();
- transitC.setAllReady();
- mSyncEngine.tryFinishForTest(transitC.getSyncId());
+ tryFinishTransitionSyncSet(transitC);
assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
}
@@ -2642,6 +2666,12 @@
assertEquals("reason1", condition1.mAlternate);
}
+ private void tryFinishTransitionSyncSet(Transition transition) {
+ transition.setAllReady();
+ transition.start();
+ mSyncEngine.tryFinishForTest(transition.getSyncId());
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {