summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java327
-rw-r--r--core/java/android/view/NotificationTopLineView.java165
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java6
-rw-r--r--core/java/com/android/internal/widget/MediaNotificationView.java120
-rw-r--r--core/res/res/layout/notification_material_media_action.xml1
-rw-r--r--core/res/res/layout/notification_material_media_seekbar.xml65
-rw-r--r--core/res/res/layout/notification_template_material_base.xml173
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml56
-rw-r--r--core/res/res/layout/notification_template_material_media.xml212
-rw-r--r--core/res/res/values/dimens.xml22
-rw-r--r--core/res/res/values/styles.xml11
-rw-r--r--core/res/res/values/symbols.xml17
-rw-r--r--core/tests/coretests/src/android/app/NotificationTest.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java219
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java366
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java181
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java15
22 files changed, 476 insertions, 1732 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5dd10f10930b..4eda6fefd188 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -20,8 +20,6 @@ import static android.annotation.Dimension.DP;
import static android.graphics.drawable.Icon.TYPE_URI;
import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
-import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
-
import static java.util.Objects.requireNonNull;
import android.annotation.AttrRes;
@@ -3701,8 +3699,6 @@ public class Notification implements Parcelable
private int mTextColorsAreForBackground = COLOR_INVALID;
private int mPrimaryTextColor = COLOR_INVALID;
private int mSecondaryTextColor = COLOR_INVALID;
- private int mBackgroundColor = COLOR_INVALID;
- private int mForegroundColor = COLOR_INVALID;
private boolean mRebuildStyledRemoteViews;
private boolean mTintActionButtons;
@@ -5041,7 +5037,8 @@ public class Notification implements Parcelable
private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p,
TemplateBindResult result) {
p.headerless(resId == getBaseLayoutResource()
- || resId == getHeadsUpBaseLayoutResource());
+ || resId == getHeadsUpBaseLayoutResource()
+ || resId == R.layout.notification_template_material_media);
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
resetStandardTemplate(contentView);
@@ -5092,7 +5089,7 @@ public class Notification implements Parcelable
}
private CharSequence processTextSpans(CharSequence text) {
- if (hasForegroundColor() || mInNightMode) {
+ if (mInNightMode) {
return ContrastColorUtil.clearColorSpans(text);
}
return text;
@@ -5103,10 +5100,6 @@ public class Notification implements Parcelable
contentView.setTextColor(id, getPrimaryTextColor(p));
}
- private boolean hasForegroundColor() {
- return mForegroundColor != COLOR_INVALID;
- }
-
/**
* @param p the template params to inflate this with
* @return the primary text color
@@ -5140,75 +5133,15 @@ public class Notification implements Parcelable
|| mSecondaryTextColor == COLOR_INVALID
|| mTextColorsAreForBackground != backgroundColor) {
mTextColorsAreForBackground = backgroundColor;
- if (!hasForegroundColor() || !isColorized(p)) {
- mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
- backgroundColor, mInNightMode);
- mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
- backgroundColor, mInNightMode);
- if (backgroundColor != COLOR_DEFAULT && isColorized(p)) {
- mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
- mPrimaryTextColor, backgroundColor, 4.5);
- mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
- mSecondaryTextColor, backgroundColor, 4.5);
- }
- } else {
- double backLum = ContrastColorUtil.calculateLuminance(backgroundColor);
- double textLum = ContrastColorUtil.calculateLuminance(mForegroundColor);
- double contrast = ContrastColorUtil.calculateContrast(mForegroundColor,
- backgroundColor);
- // We only respect the given colors if worst case Black or White still has
- // contrast
- boolean backgroundLight = backLum > textLum
- && satisfiesTextContrast(backgroundColor, Color.BLACK)
- || backLum <= textLum
- && !satisfiesTextContrast(backgroundColor, Color.WHITE);
- if (contrast < 4.5f) {
- if (backgroundLight) {
- mSecondaryTextColor = ContrastColorUtil.findContrastColor(
- mForegroundColor,
- backgroundColor,
- true /* findFG */,
- 4.5f);
- mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
- mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_LIGHT);
- } else {
- mSecondaryTextColor =
- ContrastColorUtil.findContrastColorAgainstDark(
- mForegroundColor,
- backgroundColor,
- true /* findFG */,
- 4.5f);
- mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
- mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_DARK);
- }
- } else {
- mPrimaryTextColor = mForegroundColor;
- mSecondaryTextColor = ContrastColorUtil.changeColorLightness(
- mPrimaryTextColor, backgroundLight ? LIGHTNESS_TEXT_DIFFERENCE_LIGHT
- : LIGHTNESS_TEXT_DIFFERENCE_DARK);
- if (ContrastColorUtil.calculateContrast(mSecondaryTextColor,
- backgroundColor) < 4.5f) {
- // oh well the secondary is not good enough
- if (backgroundLight) {
- mSecondaryTextColor = ContrastColorUtil.findContrastColor(
- mSecondaryTextColor,
- backgroundColor,
- true /* findFG */,
- 4.5f);
- } else {
- mSecondaryTextColor
- = ContrastColorUtil.findContrastColorAgainstDark(
- mSecondaryTextColor,
- backgroundColor,
- true /* findFG */,
- 4.5f);
- }
- mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
- mSecondaryTextColor, backgroundLight
- ? -LIGHTNESS_TEXT_DIFFERENCE_LIGHT
- : -LIGHTNESS_TEXT_DIFFERENCE_DARK);
- }
- }
+ mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
+ backgroundColor, mInNightMode);
+ mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
+ backgroundColor, mInNightMode);
+ if (backgroundColor != COLOR_DEFAULT && isColorized(p)) {
+ mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+ mPrimaryTextColor, backgroundColor, 4.5);
+ mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+ mSecondaryTextColor, backgroundColor, 4.5);
}
}
}
@@ -5254,11 +5187,7 @@ public class Notification implements Parcelable
result = new TemplateBindResult();
}
bindLargeIcon(contentView, p, result);
- if (p.mHeaderless) {
- // views in the headerless (collapsed) state
- result.mHeadingExtraMarginSet.applyToView(contentView,
- R.id.notification_headerless_view_column);
- } else {
+ if (!p.mHeaderless) {
// views in states with a header (big states)
result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header);
result.mTitleMarginSet.applyToView(contentView, R.id.title);
@@ -5278,6 +5207,8 @@ public class Notification implements Parcelable
@NonNull TemplateBindResult result) {
final Resources resources = mContext.getResources();
final float density = resources.getDisplayMetrics().density;
+ final float iconMarginDp = resources.getDimension(
+ R.dimen.notification_right_icon_content_margin) / density;
final float contentMarginDp = resources.getDimension(
R.dimen.notification_content_margin_end) / density;
final float expanderSizeDp = resources.getDimension(
@@ -5299,7 +5230,7 @@ public class Notification implements Parcelable
}
}
}
- final float extraMarginEndDpIfVisible = viewWidthDp + contentMarginDp;
+ final float extraMarginEndDpIfVisible = viewWidthDp + iconMarginDp;
result.setRightIconState(largeIconShown, viewWidthDp,
extraMarginEndDpIfVisible, expanderSizeDp);
}
@@ -5363,7 +5294,7 @@ public class Notification implements Parcelable
private void bindHeaderChronometerAndTime(RemoteViews contentView,
StandardTemplateParams p, boolean hasTextToLeft) {
- if (showsTimeOrChronometer()) {
+ if (!p.mHideTime && showsTimeOrChronometer()) {
if (hasTextToLeft) {
contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
setTextViewColorSecondary(contentView, R.id.time_divider, p);
@@ -5394,6 +5325,9 @@ public class Notification implements Parcelable
*/
private boolean bindHeaderText(RemoteViews contentView, StandardTemplateParams p,
boolean hasTextToLeft) {
+ if (p.mHideSubText) {
+ return false;
+ }
CharSequence summaryText = p.summaryText;
if (summaryText == null && mStyle != null && mStyle.mSummaryTextSet
&& mStyle.hasSummaryInHeader()) {
@@ -5424,6 +5358,9 @@ public class Notification implements Parcelable
*/
private boolean bindHeaderTextSecondary(RemoteViews contentView, StandardTemplateParams p,
boolean hasTextToLeft) {
+ if (p.mHideSubText) {
+ return false;
+ }
if (!TextUtils.isEmpty(p.headerTextSecondary)) {
contentView.setTextViewText(R.id.header_text_secondary, processTextSpans(
processLegacyText(p.headerTextSecondary)));
@@ -6654,7 +6591,7 @@ public class Notification implements Parcelable
*/
private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
if (isColorized(p)) {
- return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : getRawColor(p);
+ return getRawColor(p);
} else {
return COLOR_DEFAULT;
}
@@ -6682,21 +6619,6 @@ public class Notification implements Parcelable
}
/**
- * Set a color palette to be used as the background and textColors
- *
- * @param backgroundColor the color to be used as the background
- * @param foregroundColor the color to be used as the foreground
- *
- * @hide
- */
- public void setColorPalette(@ColorInt int backgroundColor, @ColorInt int foregroundColor) {
- mBackgroundColor = backgroundColor;
- mForegroundColor = foregroundColor;
- mTextColorsAreForBackground = COLOR_INVALID;
- ensureColors(mParams.reset().fillTextsFrom(this));
- }
-
- /**
* Forces all styled remoteViews to be built from scratch and not use any cached
* RemoteViews.
* This is needed for legacy apps that are baking in their remoteviews into the
@@ -6752,24 +6674,14 @@ public class Notification implements Parcelable
if (mLargeIcon != null || largeIcon != null) {
Resources resources = context.getResources();
Class<? extends Style> style = getNotificationStyle();
- int maxWidth = resources.getDimensionPixelSize(isLowRam
+ int maxSize = resources.getDimensionPixelSize(isLowRam
? R.dimen.notification_right_icon_size_low_ram
: R.dimen.notification_right_icon_size);
- int maxHeight = maxWidth;
- if (MediaStyle.class.equals(style)
- || DecoratedMediaCustomViewStyle.class.equals(style)) {
- maxHeight = resources.getDimensionPixelSize(isLowRam
- ? R.dimen.notification_media_image_max_height_low_ram
- : R.dimen.notification_media_image_max_height);
- maxWidth = resources.getDimensionPixelSize(isLowRam
- ? R.dimen.notification_media_image_max_width_low_ram
- : R.dimen.notification_media_image_max_width);
- }
if (mLargeIcon != null) {
- mLargeIcon.scaleDownIfNecessary(maxWidth, maxHeight);
+ mLargeIcon.scaleDownIfNecessary(maxSize, maxSize);
}
if (largeIcon != null) {
- largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxWidth, maxHeight);
+ largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxSize, maxSize);
}
}
reduceImageSizesForRemoteView(contentView, context, isLowRam);
@@ -6856,9 +6768,6 @@ public class Notification implements Parcelable
* @hide
*/
public boolean isColorized() {
- if (isColorizedMedia()) {
- return true;
- }
return extras.getBoolean(EXTRA_COLORIZED)
&& (hasColorizedPermission() || isForegroundService());
}
@@ -6872,27 +6781,6 @@ public class Notification implements Parcelable
}
/**
- * @return true if this notification is colorized and it is a media notification
- *
- * @hide
- */
- public boolean isColorizedMedia() {
- Class<? extends Style> style = getNotificationStyle();
- if (MediaStyle.class.equals(style)) {
- Boolean colorized = (Boolean) extras.get(EXTRA_COLORIZED);
- if ((colorized == null || colorized) && hasMediaSession()) {
- return true;
- }
- } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
- if (extras.getBoolean(EXTRA_COLORIZED) && hasMediaSession()) {
- return true;
- }
- }
- return false;
- }
-
-
- /**
* @return true if this is a media notification
*
* @hide
@@ -7180,15 +7068,6 @@ public class Notification implements Parcelable
/**
* @hide
- * @return true if the style positions the progress bar on the second line; false if the
- * style hides the progress bar
- */
- protected boolean hasProgress() {
- return true;
- }
-
- /**
- * @hide
* @return Whether we should put the summary be put into the notification header
*/
public boolean hasSummaryInHeader() {
@@ -9041,7 +8920,7 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
- return makeMediaContentView();
+ return makeMediaContentView(null /* customContent */);
}
/**
@@ -9049,7 +8928,7 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeBigContentView() {
- return makeMediaBigContentView();
+ return makeMediaBigContentView(null /* customContent */);
}
/**
@@ -9057,7 +8936,7 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- return makeMediaContentView();
+ return makeMediaContentView(null /* customContent */);
}
/** @hide */
@@ -9127,88 +9006,72 @@ public class Notification implements Parcelable
container.setContentDescription(buttonId, action.title);
}
- private RemoteViews makeMediaContentView() {
+ /** @hide */
+ protected RemoteViews makeMediaContentView(@Nullable RemoteViews customContent) {
+ final int numActions = mBuilder.mActions.size();
+ final int numActionsToShow = Math.min(mActionsToShowInCompact == null
+ ? 0 : mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
+ if (numActionsToShow > numActions) {
+ throw new IllegalArgumentException(String.format(
+ "setShowActionsInCompactView: action %d out of bounds (max %d)",
+ numActions, numActions - 1));
+ }
+
StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
+ .hideTime(numActionsToShow > 1) // hide if actions wider than a large icon
+ .hideSubText(numActionsToShow > 1) // hide if actions wider than a large icon
+ .hideLargeIcon(numActionsToShow > 0) // large icon or actions; not both
.hideProgress(true)
.fillTextsFrom(mBuilder);
- RemoteViews view = mBuilder.applyStandardTemplate(
+ TemplateBindResult result = new TemplateBindResult();
+ RemoteViews template = mBuilder.applyStandardTemplate(
R.layout.notification_template_material_media, p,
null /* result */);
- final int numActions = mBuilder.mActions.size();
- final int numActionsToShow = mActionsToShowInCompact == null
- ? 0
- : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
- if (numActionsToShow > numActions) {
- throw new IllegalArgumentException(String.format(
- "setShowActionsInCompactView: action %d out of bounds (max %d)",
- numActions, numActions - 1));
- }
for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) {
if (i < numActionsToShow) {
final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
- bindMediaActionButton(view, MEDIA_BUTTON_IDS[i], action, p);
+ bindMediaActionButton(template, MEDIA_BUTTON_IDS[i], action, p);
} else {
- view.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
+ template.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
}
}
- handleImage(view);
- // handle the content margin
- int endMargin = R.dimen.notification_content_margin_end;
- if (mBuilder.mN.hasLargeIcon()) {
- endMargin = R.dimen.notification_media_image_margin_end;
- }
- view.setViewLayoutMarginDimen(R.id.notification_main_column,
- RemoteViews.MARGIN_END, endMargin);
- return view;
+ // Prevent a swooping expand animation when there are no actions
+ boolean hasActions = numActionsToShow != 0;
+ template.setViewVisibility(R.id.media_actions, hasActions ? View.VISIBLE : View.GONE);
+
+ // Add custom view if provided by subclass.
+ buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
+ DevFlags.DECORATION_PARTIAL);
+ return template;
}
- private RemoteViews makeMediaBigContentView() {
+ /** @hide */
+ protected RemoteViews makeMediaBigContentView(@Nullable RemoteViews customContent) {
final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
- // Dont add an expanded view if there is no more content to be revealed
- int actionsInCompact = mActionsToShowInCompact == null
- ? 0
- : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
- if (!mBuilder.mN.hasLargeIcon() && actionCount <= actionsInCompact) {
- return null;
- }
StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_BIG)
.hideProgress(true)
.fillTextsFrom(mBuilder);
- RemoteViews big = mBuilder.applyStandardTemplate(
- R.layout.notification_template_material_big_media, p , null /* result */);
+ TemplateBindResult result = new TemplateBindResult();
+ RemoteViews template = mBuilder.applyStandardTemplate(
+ R.layout.notification_template_material_big_media, p , result);
for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) {
if (i < actionCount) {
- bindMediaActionButton(big, MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), p);
+ bindMediaActionButton(template,
+ MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), p);
} else {
- big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
+ template.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
}
}
- handleImage(big);
- return big;
- }
-
- private void handleImage(RemoteViews contentView) {
- if (mBuilder.mN.hasLargeIcon()) {
- contentView.setViewLayoutMarginDimen(R.id.title, RemoteViews.MARGIN_END, 0);
- contentView.setViewLayoutMarginDimen(R.id.text, RemoteViews.MARGIN_END, 0);
- }
- }
-
- /**
- * @hide
- */
- @Override
- protected boolean hasProgress() {
- return false;
+ buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
+ DevFlags.DECORATION_PARTIAL);
+ return template;
}
}
-
-
/**
* Helper class for generating large-format notifications that include a large image attachment.
*
@@ -9896,9 +9759,7 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
- RemoteViews remoteViews = super.makeContentView(false /* increasedHeight */);
- return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
- mBuilder.mN.contentView);
+ return makeMediaContentView(mBuilder.mN.contentView);
}
/**
@@ -9906,24 +9767,10 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeBigContentView() {
- RemoteViews customRemoteView = mBuilder.mN.bigContentView != null
+ RemoteViews customContent = mBuilder.mN.bigContentView != null
? mBuilder.mN.bigContentView
: mBuilder.mN.contentView;
- return makeBigContentViewWithCustomContent(customRemoteView);
- }
-
- private RemoteViews makeBigContentViewWithCustomContent(RemoteViews customRemoteView) {
- RemoteViews remoteViews = super.makeBigContentView();
- if (remoteViews != null) {
- return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
- customRemoteView);
- } else if (customRemoteView != mBuilder.mN.contentView){
- remoteViews = super.makeContentView(false /* increasedHeight */);
- return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
- customRemoteView);
- } else {
- return null;
- }
+ return makeMediaBigContentView(customContent);
}
/**
@@ -9931,10 +9778,10 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- RemoteViews customRemoteView = mBuilder.mN.headsUpContentView != null
+ RemoteViews customContent = mBuilder.mN.headsUpContentView != null
? mBuilder.mN.headsUpContentView
: mBuilder.mN.contentView;
- return makeBigContentViewWithCustomContent(customRemoteView);
+ return makeMediaBigContentView(customContent);
}
/**
@@ -9949,18 +9796,21 @@ public class Notification implements Parcelable
return false;
}
- private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
- RemoteViews customContent) {
+ private RemoteViews buildIntoRemoteView(RemoteViews template, RemoteViews customContent,
+ boolean headerless) {
if (customContent != null) {
// Need to clone customContent before adding, because otherwise it can no longer be
// parceled independently of remoteViews.
customContent = customContent.clone();
customContent.overrideTextColors(mBuilder.getPrimaryTextColor(mBuilder.mParams));
- remoteViews.removeAllViews(id);
- remoteViews.addView(id, customContent);
- remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
+ if (headerless) {
+ template.removeFromParent(R.id.notification_top_line);
+ }
+ template.removeAllViews(R.id.notification_main_column);
+ template.addView(R.id.notification_main_column, customContent);
+ template.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
}
- return remoteViews;
+ return template;
}
}
@@ -12253,6 +12103,8 @@ public class Notification implements Parcelable
boolean mHeaderless;
boolean mHideAppName;
boolean mHideTitle;
+ boolean mHideSubText;
+ boolean mHideTime;
boolean mHideActions;
boolean mHideProgress;
boolean mHideSnoozeButton;
@@ -12275,6 +12127,8 @@ public class Notification implements Parcelable
mHeaderless = false;
mHideAppName = false;
mHideTitle = false;
+ mHideSubText = false;
+ mHideTime = false;
mHideActions = false;
mHideProgress = false;
mHideSnoozeButton = false;
@@ -12288,6 +12142,7 @@ public class Notification implements Parcelable
summaryText = null;
headerTextSecondary = null;
maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
+ hideLargeIcon = false;
allowColorization = true;
mReduceHighlights = false;
return this;
@@ -12312,6 +12167,16 @@ public class Notification implements Parcelable
return this;
}
+ public StandardTemplateParams hideSubText(boolean hideSubText) {
+ mHideSubText = hideSubText;
+ return this;
+ }
+
+ public StandardTemplateParams hideTime(boolean hideTime) {
+ mHideTime = hideTime;
+ return this;
+ }
+
final StandardTemplateParams hideActions(boolean hideActions) {
this.mHideActions = hideActions;
return this;
diff --git a/core/java/android/view/NotificationTopLineView.java b/core/java/android/view/NotificationTopLineView.java
index 05636de8e8e4..bd20f5bf82fd 100644
--- a/core/java/android/view/NotificationTopLineView.java
+++ b/core/java/android/view/NotificationTopLineView.java
@@ -26,6 +26,9 @@ import android.widget.RemoteViews;
import com.android.internal.R;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* The top line of content in a notification view.
* This includes the text views and badges but excludes the icon and the expander.
@@ -34,17 +37,23 @@ import com.android.internal.R;
*/
@RemoteViews.RemoteView
public class NotificationTopLineView extends ViewGroup {
+ private final OverflowAdjuster mOverflowAdjuster = new OverflowAdjuster();
private final int mGravityY;
private final int mChildMinWidth;
+ private final int mChildHideWidth;
@Nullable private View mAppName;
@Nullable private View mTitle;
private View mHeaderText;
+ private View mHeaderTextDivider;
private View mSecondaryHeaderText;
+ private View mSecondaryHeaderTextDivider;
private OnClickListener mFeedbackListener;
private HeaderTouchListener mTouchListener = new HeaderTouchListener();
private View mFeedbackIcon;
private int mHeaderTextMarginEnd;
+ private Set<View> mViewsToDisappear = new HashSet<>();
+
private int mMaxAscent;
private int mMaxDescent;
@@ -66,6 +75,7 @@ public class NotificationTopLineView extends ViewGroup {
super(context, attrs, defStyleAttr, defStyleRes);
Resources res = getResources();
mChildMinWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_min_width);
+ mChildHideWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_hide_width);
// NOTE: Implementation only supports TOP, BOTTOM, and CENTER_VERTICAL gravities,
// with CENTER_VERTICAL being the default.
@@ -88,7 +98,9 @@ public class NotificationTopLineView extends ViewGroup {
mAppName = findViewById(R.id.app_name_text);
mTitle = findViewById(R.id.title);
mHeaderText = findViewById(R.id.header_text);
+ mHeaderTextDivider = findViewById(R.id.header_text_divider);
mSecondaryHeaderText = findViewById(R.id.header_text_secondary);
+ mSecondaryHeaderTextDivider = findViewById(R.id.header_text_secondary_divider);
mFeedbackIcon = findViewById(R.id.feedback);
}
@@ -125,48 +137,37 @@ public class NotificationTopLineView extends ViewGroup {
maxChildHeight = Math.max(maxChildHeight, childHeight);
}
+ mViewsToDisappear.clear();
// Ensure that there is at least enough space for the icons
int endMargin = Math.max(mHeaderTextMarginEnd, getPaddingEnd());
if (totalWidth > givenWidth - endMargin) {
int overFlow = totalWidth - givenWidth + endMargin;
- // First shrink the app name, down to a minimum size
- overFlow = shrinkViewForOverflow(heightSpec, overFlow, mAppName, mChildMinWidth);
-
- // Next, shrink the header text (this usually has subText)
- // This shrinks the subtext first, but not all the way (yet!)
- overFlow = shrinkViewForOverflow(heightSpec, overFlow, mHeaderText, mChildMinWidth);
-
- // Next, shrink the secondary header text (this rarely has conversationTitle)
- overFlow = shrinkViewForOverflow(heightSpec, overFlow, mSecondaryHeaderText, 0);
-
- // Next, shrink the title text (this has contentTitle; only in headerless views)
- overFlow = shrinkViewForOverflow(heightSpec, overFlow, mTitle, mChildMinWidth);
-
- // Finally, if there is still overflow, shrink the header down to 0 if still necessary.
- shrinkViewForOverflow(heightSpec, overFlow, mHeaderText, 0);
+ mOverflowAdjuster.resetForOverflow(overFlow, heightSpec)
+ // First shrink the app name, down to a minimum size
+ .adjust(mAppName, null, mChildMinWidth)
+ // Next, shrink the header text (this usually has subText)
+ // This shrinks the subtext first, but not all the way (yet!)
+ .adjust(mHeaderText, mHeaderTextDivider, mChildMinWidth)
+ // Next, shrink the secondary header text (this rarely has conversationTitle)
+ .adjust(mSecondaryHeaderText, mSecondaryHeaderTextDivider, 0)
+ // Next, shrink the title text (this has contentTitle; only in headerless views)
+ .adjust(mTitle, null, mChildMinWidth)
+ // Next, shrink the header down to 0 if still necessary.
+ .adjust(mHeaderText, mHeaderTextDivider, 0)
+ // Finally, shrink the title to 0 if necessary (media is super cramped)
+ .adjust(mTitle, null, 0)
+ // Clean up
+ .finish();
}
setMeasuredDimension(givenWidth, wrapHeight ? maxChildHeight : givenHeight);
}
- private int shrinkViewForOverflow(int heightSpec, int overFlow, View targetView,
- int minimumWidth) {
- if (targetView != null) {
- final int oldWidth = targetView.getMeasuredWidth();
- if (overFlow > 0 && targetView.getVisibility() != GONE && oldWidth > minimumWidth) {
- // we're still too big
- int newSize = Math.max(minimumWidth, oldWidth - overFlow);
- int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
- targetView.measure(childWidthSpec, heightSpec);
- overFlow -= oldWidth - newSize;
- }
- }
- return overFlow;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int left = getPaddingStart();
+ final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ final int width = getWidth();
+ int start = getPaddingStart();
int childCount = getChildCount();
int ownHeight = b - t;
int childSpace = ownHeight - mPaddingTop - mPaddingBottom;
@@ -182,8 +183,6 @@ public class NotificationTopLineView extends ViewGroup {
}
int childHeight = child.getMeasuredHeight();
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
- int layoutLeft;
- int layoutRight;
// Calculate vertical alignment of the views, accounting for the view baselines
int childTop;
@@ -219,19 +218,16 @@ public class NotificationTopLineView extends ViewGroup {
default:
childTop = mPaddingTop;
}
-
- left += params.getMarginStart();
- int right = left + child.getMeasuredWidth();
- layoutLeft = left;
- layoutRight = right;
- left = right + params.getMarginEnd();
-
- if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
- int ltrLeft = layoutLeft;
- layoutLeft = getWidth() - layoutRight;
- layoutRight = getWidth() - ltrLeft;
+ if (mViewsToDisappear.contains(child)) {
+ child.layout(start, childTop, start, childTop + childHeight);
+ } else {
+ start += params.getMarginStart();
+ int end = start + child.getMeasuredWidth();
+ int layoutLeft = isRtl ? width - end : start;
+ int layoutRight = isRtl ? width - start : end;
+ start = end + params.getMarginEnd();
+ child.layout(layoutLeft, childTop, layoutRight, childTop + childHeight);
}
- child.layout(layoutLeft, childTop, layoutRight, childTop + childHeight);
}
updateTouchListener();
}
@@ -400,4 +396,83 @@ public class NotificationTopLineView extends ViewGroup {
}
return mTouchListener.onTouchUp(upX, upY, downX, downY);
}
+
+ private final class OverflowAdjuster {
+ private int mOverflow;
+ private int mHeightSpec;
+ private View mRegrowView;
+
+ OverflowAdjuster resetForOverflow(int overflow, int heightSpec) {
+ mOverflow = overflow;
+ mHeightSpec = heightSpec;
+ mRegrowView = null;
+ return this;
+ }
+
+ /**
+ * Shrink the targetView's width by up to overFlow, down to minimumWidth.
+ * @param targetView the view to shrink the width of
+ * @param targetDivider a divider view which should be set to 0 width if the targetView is
+ * @param minimumWidth the minimum width allowed for the targetView
+ * @return this object
+ */
+ OverflowAdjuster adjust(View targetView, View targetDivider, int minimumWidth) {
+ if (mOverflow <= 0 || targetView == null || targetView.getVisibility() == View.GONE) {
+ return this;
+ }
+ final int oldWidth = targetView.getMeasuredWidth();
+ if (oldWidth <= minimumWidth) {
+ return this;
+ }
+ // we're too big
+ int newSize = Math.max(minimumWidth, oldWidth - mOverflow);
+ if (minimumWidth == 0 && newSize < mChildHideWidth
+ && mRegrowView != null && mRegrowView != targetView) {
+ // View is so small it's better to hide it entirely (and its divider and margins)
+ // so we can give that space back to another previously shrunken view.
+ newSize = 0;
+ }
+
+ int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
+ targetView.measure(childWidthSpec, mHeightSpec);
+ mOverflow -= oldWidth - newSize;
+
+ if (newSize == 0) {
+ mViewsToDisappear.add(targetView);
+ mOverflow -= getHorizontalMargins(targetView);
+ if (targetDivider != null && targetDivider.getVisibility() != GONE) {
+ mViewsToDisappear.add(targetDivider);
+ int oldDividerWidth = targetDivider.getMeasuredWidth();
+ int dividerWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.AT_MOST);
+ targetDivider.measure(dividerWidthSpec, mHeightSpec);
+ mOverflow -= (oldDividerWidth + getHorizontalMargins(targetDivider));
+ }
+ }
+ if (mOverflow < 0 && mRegrowView != null) {
+ // We're now under-flowing, so regrow the last view.
+ final int regrowCurrentSize = mRegrowView.getMeasuredWidth();
+ final int maxSize = regrowCurrentSize - mOverflow;
+ int regrowWidthSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+ mRegrowView.measure(regrowWidthSpec, mHeightSpec);
+ finish();
+ return this;
+ }
+
+ if (newSize != 0) {
+ // if we shrunk this view (but did not completely hide it) store it for potential
+ // re-growth if we proactively shorten a future view.
+ mRegrowView = targetView;
+ }
+ return this;
+ }
+
+ void finish() {
+ resetForOverflow(0, 0);
+ }
+
+ private int getHorizontalMargins(View view) {
+ MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
+ return params.getMarginStart() + params.getMarginEnd();
+ }
+ }
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 02cbccc77c3f..a5b894dff46d 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -130,12 +130,6 @@ public final class SystemUiDeviceConfigFlags {
// Flags related to media notifications
/**
- * (boolean) If {@code true}, enables the seekbar in compact media notifications.
- */
- public static final String COMPACT_MEDIA_SEEKBAR_ENABLED =
- "compact_media_notification_seekbar_enabled";
-
- /**
* (int) Maximum number of days to retain the salt for hashing direct share targets in logging
*/
public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days";
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index f42d5da30b19..8ff3c106d229 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -19,31 +19,19 @@ package com.android.internal.widget;
import android.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.NotificationHeaderView;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.RemoteViews;
import java.util.ArrayList;
/**
- * A TextView that can float around an image on the end.
+ * The Layout class which handles template details for the Notification.MediaStyle
*
* @hide
*/
@RemoteViews.RemoteView
public class MediaNotificationView extends FrameLayout {
- private final int mNotificationContentMarginEnd;
- private final int mNotificationContentImageMarginEnd;
- private ImageView mRightIcon;
- private View mActions;
- private NotificationHeaderView mHeader;
- private View mMainColumn;
- private View mMediaContent;
- private int mImagePushIn;
private ArrayList<VisibilityChangeListener> mListeners;
public MediaNotificationView(Context context) {
@@ -58,120 +46,14 @@ public class MediaNotificationView extends FrameLayout {
this(context, attrs, defStyleAttr, 0);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- boolean hasIcon = mRightIcon.getVisibility() != GONE;
- if (!hasIcon) {
- resetHeaderIndention();
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int mode = MeasureSpec.getMode(widthMeasureSpec);
- boolean reMeasure = false;
- mImagePushIn = 0;
- if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
- int size = MeasureSpec.getSize(widthMeasureSpec);
- size = size - mActions.getMeasuredWidth();
- ViewGroup.MarginLayoutParams layoutParams =
- (MarginLayoutParams) mRightIcon.getLayoutParams();
- int imageEndMargin = layoutParams.getMarginEnd();
- size -= imageEndMargin;
- int fullHeight = mMediaContent.getMeasuredHeight();
- if (size > fullHeight) {
- size = fullHeight;
- } else if (size < fullHeight) {
- size = Math.max(0, size);
- mImagePushIn = fullHeight - size;
- }
- if (layoutParams.width != fullHeight || layoutParams.height != fullHeight) {
- layoutParams.width = fullHeight;
- layoutParams.height = fullHeight;
- mRightIcon.setLayoutParams(layoutParams);
- reMeasure = true;
- }
-
- // lets ensure that the main column doesn't run into the image
- ViewGroup.MarginLayoutParams params
- = (MarginLayoutParams) mMainColumn.getLayoutParams();
- int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
- if (marginEnd != params.getMarginEnd()) {
- params.setMarginEnd(marginEnd);
- mMainColumn.setLayoutParams(params);
- reMeasure = true;
- }
- // TODO(b/172652345): validate all this logic (especially positioning of expand button)
- // margin for the entire header line
- int headerMarginEnd = imageEndMargin;
- // margin for the header text (not including the expand button and other icons)
- int headerExtraMarginEnd = Math.max(0,
- size + imageEndMargin - mHeader.getTopLineBaseMarginEnd());
- if (headerExtraMarginEnd != mHeader.getTopLineExtraMarginEnd()) {
- mHeader.setTopLineExtraMarginEnd(headerExtraMarginEnd);
- reMeasure = true;
- }
- params = (MarginLayoutParams) mHeader.getLayoutParams();
- if (params.getMarginEnd() != headerMarginEnd) {
- params.setMarginEnd(headerMarginEnd);
- mHeader.setLayoutParams(params);
- reMeasure = true;
- }
- if (mHeader.getPaddingEnd() != mNotificationContentImageMarginEnd) {
- mHeader.setPaddingRelative(mHeader.getPaddingStart(),
- mHeader.getPaddingTop(),
- mNotificationContentImageMarginEnd,
- mHeader.getPaddingBottom());
- reMeasure = true;
- }
- }
- if (reMeasure) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mImagePushIn > 0) {
- if (this.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
- mImagePushIn *= -1;
- }
- mRightIcon.layout(mRightIcon.getLeft() + mImagePushIn, mRightIcon.getTop(),
- mRightIcon.getRight() + mImagePushIn, mRightIcon.getBottom());
- }
- }
-
- private void resetHeaderIndention() {
- if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
- mHeader.setPaddingRelative(mHeader.getPaddingStart(),
- mHeader.getPaddingTop(),
- mNotificationContentMarginEnd,
- mHeader.getPaddingBottom());
- }
- ViewGroup.MarginLayoutParams headerParams =
- (MarginLayoutParams) mHeader.getLayoutParams();
- headerParams.setMarginEnd(0);
- if (headerParams.getMarginEnd() != 0) {
- headerParams.setMarginEnd(0);
- mHeader.setLayoutParams(headerParams);
- }
- }
-
public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_end);
- mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_image_margin_end);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mRightIcon = findViewById(com.android.internal.R.id.right_icon);
- mActions = findViewById(com.android.internal.R.id.media_actions);
- mHeader = findViewById(com.android.internal.R.id.notification_header);
- mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
- mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
}
@Override
diff --git a/core/res/res/layout/notification_material_media_action.xml b/core/res/res/layout/notification_material_media_action.xml
index dd79a0bb1817..5f1b60e8d0f2 100644
--- a/core/res/res/layout/notification_material_media_action.xml
+++ b/core/res/res/layout/notification_material_media_action.xml
@@ -24,7 +24,6 @@
android:paddingTop="8dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
- android:layout_marginEnd="2dp"
android:gravity="center"
android:background="@drawable/notification_material_media_action_background"
android:visibility="gone"
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
deleted file mode 100644
index 4aa8acc363fa..000000000000
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 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
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/notification_media_progress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_alignParentBottom="true"
- >
- <SeekBar android:id="@+id/notification_media_progress_bar"
- style="@style/Widget.ProgressBar.Horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxHeight="3dp"
- android:paddingTop="24dp"
- android:paddingBottom="24dp"
- android:clickable="true"
- android:layout_marginBottom="-24dp"
- android:layout_marginTop="-12dp"
- android:splitTrack="false"
- />
- <FrameLayout
- android:id="@+id/notification_media_progress_time"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginBottom="11dp"
- >
-
- <!-- width is set to "match_parent" to avoid extra layout calls -->
- <TextView android:id="@+id/notification_media_elapsed_time"
- style="@style/Widget.DeviceDefault.Notification.Text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:gravity="start"
- />
-
- <TextView android:id="@+id/notification_media_total_time"
- style="@style/Widget.DeviceDefault.Notification.Text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:gravity="end"
- />
- </FrameLayout>
-</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index bad9a6ba6184..e644cd55a86a 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -46,20 +46,6 @@
android:padding="@dimen/notification_icon_circle_padding"
/>
- <ImageView
- android:id="@+id/right_icon"
- android:layout_width="@dimen/notification_right_icon_size"
- android:layout_height="@dimen/notification_right_icon_size"
- android:layout_gravity="center_vertical|end"
- android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
- android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
- android:layout_marginEnd="@dimen/notification_header_expand_icon_size"
- android:background="@drawable/notification_large_icon_outline"
- android:clipToOutline="true"
- android:importantForAccessibility="no"
- android:scaleType="centerCrop"
- />
-
<FrameLayout
android:id="@+id/alternate_expand_target"
android:layout_width="@dimen/notification_content_margin_start"
@@ -68,95 +54,116 @@
android:importantForAccessibility="no"
/>
- <FrameLayout
- android:id="@+id/expand_button_touch_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="end">
-
- <include layout="@layout/notification_expand_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
- />
-
- </FrameLayout>
-
<LinearLayout
- android:id="@+id/notification_headerless_view_column"
+ android:id="@+id/notification_headerless_view_row"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
- android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
- android:orientation="vertical"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:orientation="horizontal"
>
- <!-- extends ViewGroup -->
- <NotificationTopLineView
- android:id="@+id/notification_top_line"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_headerless_line_height"
- android:layout_marginEnd="@dimen/notification_heading_margin_end"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:clipChildren="false"
- android:theme="@style/Theme.DeviceDefault.Notification"
+ <LinearLayout
+ android:id="@+id/notification_headerless_view_column"
+ android:layout_width="0px"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+ android:orientation="vertical"
>
- <!--
- NOTE: The notification_top_line_views layout contains the app_name_text.
- In order to include the title view at the beginning, the Notification.Builder
- has logic to hide that view whenever this title view is to be visible.
- -->
-
- <TextView
- android:id="@+id/title"
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/notification_header_separating_margin"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:textAlignment="viewStart"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- />
+ android:layout_height="@dimen/notification_headerless_line_height"
+ android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
- <include layout="@layout/notification_top_line_views" />
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
- </NotificationTopLineView>
+ <include layout="@layout/notification_top_line_views" />
- <LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/notification_heading_margin_end"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:orientation="vertical"
- >
+ </NotificationTopLineView>
- <com.android.internal.widget.NotificationVanishingFrameLayout
+ <LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_headerless_line_height"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
>
- <!-- This is the simplest way to keep this text vertically centered without using
- gravity="center_vertical" which causes jumpiness in expansion animations. -->
+
+ <com.android.internal.widget.NotificationVanishingFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ >
+ <!-- This is the simplest way to keep this text vertically centered without
+ gravity="center_vertical" which causes jumpiness in expansion animations. -->
+ <include
+ layout="@layout/notification_template_text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_text_height"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="0dp"
+ />
+ </com.android.internal.widget.NotificationVanishingFrameLayout>
+
<include
- layout="@layout/notification_template_text"
+ layout="@layout/notification_template_progress"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_text_height"
- android:layout_gravity="center_vertical"
- android:layout_marginTop="0dp"
+ android:layout_height="@dimen/notification_headerless_line_height"
/>
- </com.android.internal.widget.NotificationVanishingFrameLayout>
- <include
- layout="@layout/notification_template_progress"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_headerless_line_height"
- />
+ </LinearLayout>
</LinearLayout>
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ />
+
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
</LinearLayout>
</com.android.internal.widget.NotificationMaxHeightFrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index aa20ad36720b..ff64315572ca 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -20,17 +20,8 @@
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="#00000000"
android:tag="bigMediaNarrow"
>
- <!-- The size will actually be determined at runtime -->
- <ImageView
- android:id="@+id/right_icon"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_gravity="top|end"
- android:scaleType="centerCrop"
- />
<include
layout="@layout/notification_template_header"
@@ -49,46 +40,27 @@
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="46dp"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginBottom="@dimen/notification_content_margin"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:orientation="vertical"
>
- <!-- TODO(b/172652345): fix the media style -->
- <!--<include layout="@layout/notification_template_part_line1"/>-->
- <!--<include layout="@layout/notification_template_text"/>-->
-
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:textAlignment="viewStart"
- />
-
- <com.android.internal.widget.ImageFloatingTextView
- style="@style/Widget.DeviceDefault.Notification.Text"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_text_height"
- android:layout_gravity="top"
- android:layout_marginTop="0.5dp"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:gravity="top"
- android:singleLine="true"
- android:textAlignment="viewStart"
- />
+ <include layout="@layout/notification_template_part_line1"/>
+ <include layout="@layout/notification_template_text"/>
</LinearLayout>
<LinearLayout
android:id="@+id/media_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-21dp"
+ android:paddingStart="44dp"
+ android:paddingEnd="44dp"
+ android:paddingBottom="@dimen/media_notification_actions_padding_bottom"
+ android:gravity="top"
android:orientation="horizontal"
android:layoutDirection="ltr"
- style="@style/NotificationMediaActionContainer"
>
<include
@@ -117,10 +89,8 @@
/>
</LinearLayout>
- <ViewStub
- android:id="@+id/notification_media_seekbar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
</LinearLayout>
+
+ <include layout="@layout/notification_template_right_icon" />
+
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 542e59df76c0..2991b1706a64 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -19,101 +19,173 @@
android:id="@+id/status_bar_latest_event_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#00000000"
+ android:layout_height="@dimen/notification_min_height"
android:tag="media"
>
- <ImageView android:id="@+id/right_icon"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:adjustViewBounds="true"
- android:layout_gravity="top|end"
+
+
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_left_icon_size"
+ android:layout_height="@dimen/notification_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
android:scaleType="centerCrop"
- />
- <include layout="@layout/notification_template_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/media_notification_header_height"
+ android:visibility="gone"
+ />
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_icon_circle_size"
+ android:layout_height="@dimen/notification_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_icon_circle_padding"
+ />
+
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
/>
+
<LinearLayout
+ android:id="@+id/notification_headerless_view_row"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:id="@+id/notification_media_content"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:orientation="horizontal"
>
+
<LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
+ android:id="@+id/notification_headerless_view_column"
+ android:layout_width="0px"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginTop="46dp"
- android:layout_alignParentTop="true"
- android:tag="media"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+ android:orientation="vertical"
>
- <LinearLayout
- android:id="@+id/notification_content_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_vertical"
- android:layout_weight="1"
- android:paddingBottom="@dimen/notification_content_margin"
- android:orientation="vertical"
+
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
>
- <!-- TODO(b/172652345): fix the media style -->
- <!--<include layout="@layout/notification_template_part_line1"/>-->
- <!--<include layout="@layout/notification_template_text"/>-->
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:textAlignment="viewStart"
- />
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
- <com.android.internal.widget.ImageFloatingTextView
- style="@style/Widget.DeviceDefault.Notification.Text"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_text_height"
- android:layout_gravity="top"
- android:layout_marginTop="0.5dp"
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:gravity="top"
android:singleLine="true"
android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
/>
- </LinearLayout>
+
+ <include layout="@layout/notification_top_line_views" />
+
+ </NotificationTopLineView>
+
<LinearLayout
- android:id="@+id/media_actions"
- android:layout_width="wrap_content"
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="top|end"
- android:layout_marginStart="10dp"
- android:layoutDirection="ltr"
- android:orientation="horizontal"
+ android:orientation="vertical"
>
+
+ <com.android.internal.widget.NotificationVanishingFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ >
+ <!-- This is the simplest way to keep this text vertically centered without
+ gravity="center_vertical" which causes jumpiness in expansion animations. -->
+ <include
+ layout="@layout/notification_template_text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_text_height"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="0dp"
+ />
+ </com.android.internal.widget.NotificationVanishingFrameLayout>
+
<include
- layout="@layout/notification_material_media_action"
- android:id="@+id/action0"
+ layout="@layout/notification_template_progress"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ />
+
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layoutDirection="ltr"
+ android:orientation="horizontal"
+ >
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action0"
/>
- <include
- layout="@layout/notification_material_media_action"
- android:id="@+id/action1"
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action1"
/>
- <include
- layout="@layout/notification_material_media_action"
- android:id="@+id/action2"
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action2"
/>
- </LinearLayout>
</LinearLayout>
- <ViewStub android:id="@+id/notification_media_seekbar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- />
+
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
</LinearLayout>
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 43dbd38d1dc4..afbbe467078c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -226,9 +226,6 @@
<!-- The margin on the end of the top-line content views (accommodates the expander) -->
<dimen name="notification_heading_margin_end">56dp</dimen>
- <!-- The margin for text at the end of the image view for media notifications -->
- <dimen name="notification_media_image_margin_end">72dp</dimen>
-
<!-- The height of the notification action list -->
<dimen name="notification_action_list_height">60dp</dimen>
@@ -345,6 +342,9 @@
<!-- The minimum width of the app name in the header if it shrinks -->
<dimen name="notification_header_shrink_min_width">72dp</dimen>
+ <!-- The minimum width of optional header fields below which the view is simply hidden -->
+ <dimen name="notification_header_shrink_hide_width">24sp</dimen>
+
<!-- The size of the media actions in the media notification. -->
<dimen name="media_notification_action_button_size">48dp</dimen>
@@ -360,9 +360,6 @@
<!-- The absolute height for the header in a media notification. -->
<dimen name="media_notification_header_height">@dimen/notification_header_height</dimen>
- <!-- The margin of the content to an image-->
- <dimen name="notification_content_image_margin_end">8dp</dimen>
-
<!-- The padding at the end of actions when the snooze and bubble buttons are gone-->
<dimen name="snooze_and_bubble_gone_padding_end">12dp</dimen>
@@ -483,9 +480,6 @@
<!-- Top padding for notification when text is large and narrow (i.e. it has 3 lines -->
<dimen name="notification_top_pad_large_text_narrow">-4dp</dimen>
- <!-- Padding for notification icon when drawn with circle around it -->
- <dimen name="notification_large_icon_circle_padding">11dp</dimen>
-
<!-- The margin on top of the text of the notification -->
<dimen name="notification_text_margin_top">6dp</dimen>
@@ -736,12 +730,10 @@
<dimen name="notification_big_picture_max_height">284dp</dimen>
<!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. This value is determined by the standard panel size -->
<dimen name="notification_big_picture_max_width">416dp</dimen>
- <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. This value is determined by the expanded media template-->
- <dimen name="notification_media_image_max_height">140dp</dimen>
- <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
- <dimen name="notification_media_image_max_width">280dp</dimen>
<!-- The size of the right icon -->
<dimen name="notification_right_icon_size">48dp</dimen>
+ <!-- The margin between the right icon and the content. -->
+ <dimen name="notification_right_icon_content_margin">12dp</dimen>
<!-- The top and bottom margin of the right icon in the normal notification states -->
<dimen name="notification_right_icon_headerless_margin">20dp</dimen>
<!-- The top margin of the right icon in the "big" notification states -->
@@ -762,10 +754,6 @@
<dimen name="notification_big_picture_max_height_low_ram">208dp</dimen>
<!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. -->
<dimen name="notification_big_picture_max_width_low_ram">294dp</dimen>
- <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. -->
- <dimen name="notification_media_image_max_height_low_ram">100dp</dimen>
- <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
- <dimen name="notification_media_image_max_width_low_ram">100dp</dimen>
<!-- The size of the right icon image when on low ram -->
<dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen>
<!-- The maximum size of the grayscale icon -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c7ded0cfa3a2..fbf67e0d84ac 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1481,17 +1481,6 @@ please see styles_device_defaults.xml.
<item name="android:windowExitAnimation">@anim/slide_out_down</item>
</style>
- <!-- The style for the container of media actions in a notification. -->
- <!-- @hide -->
- <style name="NotificationMediaActionContainer">
- <item name="layout_width">wrap_content</item>
- <item name="layout_height">wrap_content</item>
- <item name="layout_marginTop">-21dp</item>
- <item name="paddingStart">8dp</item>
- <item name="paddingBottom">@dimen/media_notification_actions_padding_bottom</item>
- <item name="gravity">top</item>
- </style>
-
<!-- The style for normal action button on notification -->
<style name="NotificationAction" parent="Widget.Material.Light.Button.Borderless.Small">
<item name="textColor">@color/notification_action_button_text_color</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1d74d85fb9db..d6a6f4dea220 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -200,12 +200,7 @@
<java-symbol type="id" name="action2" />
<java-symbol type="id" name="action3" />
<java-symbol type="id" name="action4" />
- <java-symbol type="id" name="notification_media_seekbar_container" />
<java-symbol type="id" name="notification_media_content" />
- <java-symbol type="id" name="notification_media_progress" />
- <java-symbol type="id" name="notification_media_progress_bar" />
- <java-symbol type="id" name="notification_media_elapsed_time" />
- <java-symbol type="id" name="notification_media_total_time" />
<java-symbol type="id" name="big_picture" />
<java-symbol type="id" name="big_text" />
<java-symbol type="id" name="chronometer" />
@@ -525,7 +520,6 @@
<java-symbol type="dimen" name="notification_top_pad_narrow" />
<java-symbol type="dimen" name="notification_top_pad_large_text" />
<java-symbol type="dimen" name="notification_top_pad_large_text_narrow" />
- <java-symbol type="dimen" name="notification_large_icon_circle_padding" />
<java-symbol type="dimen" name="notification_badge_size" />
<java-symbol type="dimen" name="immersive_mode_cling_width" />
<java-symbol type="dimen" name="accessibility_magnification_indicator_width" />
@@ -1564,7 +1558,6 @@
<java-symbol type="layout" name="immersive_mode_cling" />
<java-symbol type="layout" name="user_switching_dialog" />
<java-symbol type="layout" name="common_tab_settings" />
- <java-symbol type="layout" name="notification_material_media_seekbar" />
<java-symbol type="layout" name="resolver_list_per_profile" />
<java-symbol type="layout" name="chooser_list_per_profile" />
<java-symbol type="layout" name="resolver_empty_states" />
@@ -2921,6 +2914,7 @@
<java-symbol type="drawable" name="ic_expand_bundle" />
<java-symbol type="drawable" name="ic_collapse_bundle" />
<java-symbol type="dimen" name="notification_header_shrink_min_width" />
+ <java-symbol type="dimen" name="notification_header_shrink_hide_width" />
<java-symbol type="dimen" name="notification_content_margin_start" />
<java-symbol type="dimen" name="notification_content_margin_end" />
<java-symbol type="dimen" name="notification_heading_margin_end" />
@@ -3010,7 +3004,6 @@
<java-symbol type="string" name="new_sms_notification_content" />
<java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
- <java-symbol type="dimen" name="notification_content_image_margin_end" />
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
@@ -3019,8 +3012,6 @@
<java-symbol type="id" name="aerr_wait" />
- <java-symbol type="id" name="notification_content_container" />
-
<java-symbol type="plurals" name="duration_minutes_shortest" />
<java-symbol type="plurals" name="duration_hours_shortest" />
<java-symbol type="plurals" name="duration_days_shortest" />
@@ -3138,7 +3129,6 @@
<java-symbol type="bool" name="config_supportPreRebootSecurityLogs" />
- <java-symbol type="dimen" name="notification_media_image_margin_end" />
<java-symbol type="id" name="notification_action_list_margin_target" />
<java-symbol type="dimen" name="notification_action_disabled_alpha" />
<java-symbol type="id" name="tag_margin_end_when_icon_visible" />
@@ -3461,17 +3451,14 @@
<java-symbol type="dimen" name="notification_big_picture_max_height"/>
<java-symbol type="dimen" name="notification_big_picture_max_width"/>
- <java-symbol type="dimen" name="notification_media_image_max_width"/>
- <java-symbol type="dimen" name="notification_media_image_max_height"/>
<java-symbol type="dimen" name="notification_right_icon_size"/>
+ <java-symbol type="dimen" name="notification_right_icon_content_margin"/>
<java-symbol type="dimen" name="notification_actions_icon_drawable_size"/>
<java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
<java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
<java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
<java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
- <java-symbol type="dimen" name="notification_media_image_max_width_low_ram"/>
- <java-symbol type="dimen" name="notification_media_image_max_height_low_ram"/>
<java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>
<java-symbol type="dimen" name="notification_grayscale_icon_max_size"/>
<java-symbol type="dimen" name="notification_custom_view_max_image_height_low_ram"/>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 252938abffdb..0ea63643d24e 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -16,8 +16,6 @@
package android.app;
-import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
@@ -99,23 +97,6 @@ public class NotificationTest {
}
@Test
- public void testColorSatisfiedWhenBgDarkTextDarker() {
- Notification.Builder builder = getMediaNotification();
- Notification n = builder.build();
-
- assertTrue(n.isColorized());
-
- // An initial guess where the foreground color is actually darker than an already dark bg
- int backgroundColor = 0xff585868;
- int initialForegroundColor = 0xff505868;
- builder.setColorPalette(backgroundColor, initialForegroundColor);
- int primaryTextColor = builder.getPrimaryTextColor(builder.mParams);
- assertTrue(satisfiesTextContrast(primaryTextColor, backgroundColor));
- int secondaryTextColor = builder.getSecondaryTextColor(builder.mParams);
- assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor));
- }
-
- @Test
public void testHasCompletedProgress_noProgress() {
Notification n = new Notification.Builder(mContext).build();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index ca3923f06a13..c565a271bdd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -38,8 +38,6 @@ import android.media.session.PlaybackState;
import android.os.AsyncTask;
import android.os.Trace;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
@@ -48,7 +46,6 @@ import android.util.Log;
import android.view.View;
import android.widget.ImageView;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
@@ -147,23 +144,6 @@ public class NotificationMediaManager implements Dumpable {
private ImageView mBackdropFront;
private ImageView mBackdropBack;
- private boolean mShowCompactMediaSeekbar;
- private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
- new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(Properties properties) {
- for (String name : properties.getKeyset()) {
- if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
- String value = properties.getString(name, null);
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
- }
- mShowCompactMediaSeekbar = "true".equals(value);
- }
- }
- }
- };
-
private final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -231,14 +211,6 @@ public class NotificationMediaManager implements Dumpable {
setupNotifPipeline();
mUsingNotifPipeline = true;
}
-
- mShowCompactMediaSeekbar = "true".equals(
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
-
- deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- mContext.getMainExecutor(),
- mPropertiesChangedListener);
}
private void setupNotifPipeline() {
@@ -405,10 +377,6 @@ public class NotificationMediaManager implements Dumpable {
return mMediaMetadata;
}
- public boolean getShowCompactMediaSeekbar() {
- return mShowCompactMediaSeekbar;
- }
-
public Icon getMediaIcon() {
if (mMediaNotificationKey == null) {
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
deleted file mode 100644
index f5a76f0499e2..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-
-/**
- * A utility class to colorize bitmaps with a color gradient and a special blending mode
- */
-public class ImageGradientColorizer {
- public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
- int width = drawable.getIntrinsicWidth();
- int height = drawable.getIntrinsicHeight();
- int size = Math.min(width, height);
- int widthInset = (width - size) / 2;
- int heightInset = (height - size) / 2;
- drawable = drawable.mutate();
- drawable.setBounds(- widthInset, - heightInset, width - widthInset, height - heightInset);
- Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(newBitmap);
-
- // Values to calculate the luminance of a color
- float lr = 0.2126f;
- float lg = 0.7152f;
- float lb = 0.0722f;
-
- // Extract the red, green, blue components of the color extraction color in
- // float and int form
- int tri = Color.red(backgroundColor);
- int tgi = Color.green(backgroundColor);
- int tbi = Color.blue(backgroundColor);
-
- float tr = tri / 255f;
- float tg = tgi / 255f;
- float tb = tbi / 255f;
-
- // Calculate the luminance of the color extraction color
- float cLum = (tr * lr + tg * lg + tb * lb) * 255;
-
- ColorMatrix m = new ColorMatrix(new float[] {
- lr, lg, lb, 0, tri - cLum,
- lr, lg, lb, 0, tgi - cLum,
- lr, lg, lb, 0, tbi - cLum,
- 0, 0, 0, 1, 0,
- });
-
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- LinearGradient linearGradient = new LinearGradient(0, 0, size, 0,
- new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
- new float[] {0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP);
- paint.setShader(linearGradient);
- Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas fadeInCanvas = new Canvas(fadeIn);
- drawable.clearColorFilter();
- drawable.draw(fadeInCanvas);
-
- if (isRtl) {
- // Let's flip the gradient
- fadeInCanvas.translate(size, 0);
- fadeInCanvas.scale(-1, 1);
- }
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
- fadeInCanvas.drawPaint(paint);
-
- Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- coloredPaint.setColorFilter(new ColorMatrixColorFilter(m));
- coloredPaint.setAlpha((int) (0.5f * 255));
- canvas.drawBitmap(fadeIn, 0, 0, coloredPaint);
-
- linearGradient = new LinearGradient(0, 0, size, 0,
- new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
- new float[] {0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
- paint.setShader(linearGradient);
- fadeInCanvas.drawPaint(paint);
- canvas.drawBitmap(fadeIn, 0, 0, null);
-
- return newBitmap;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index 2586e9403e01..732c115571f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -16,237 +16,30 @@
package com.android.systemui.statusbar.notification;
-import android.app.Notification;
-import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.util.LayoutDirection;
-import androidx.annotation.VisibleForTesting;
import androidx.palette.graphics.Palette;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.settingslib.Utils;
-
import java.util.List;
/**
- * A class the processes media notifications and extracts the right text and background colors.
+ * A gutted class that now contains only a color extraction utility used by the
+ * MediaArtworkProcessor, which has otherwise supplanted this.
+ *
+ * TODO(b/182926117): move this into MediaArtworkProcessor.kt
*/
public class MediaNotificationProcessor {
/**
- * The fraction below which we select the vibrant instead of the light/dark vibrant color
- */
- private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f;
-
- /**
- * Minimum saturation that a muted color must have if there exists if deciding between two
- * colors
- */
- private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f;
-
- /**
- * Minimum fraction that any color must have to be picked up as a text color
- */
- private static final double MINIMUM_IMAGE_FRACTION = 0.002;
-
- /**
- * The population fraction to select the dominant color as the text color over a the colored
- * ones.
- */
- private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f;
-
- /**
* The population fraction to select a white or black color as the background over a color.
*/
private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f;
private static final float BLACK_MAX_LIGHTNESS = 0.08f;
private static final float WHITE_MIN_LIGHTNESS = 0.90f;
private static final int RESIZE_BITMAP_AREA = 150 * 150;
- private final ImageGradientColorizer mColorizer;
- private final Context mContext;
- private final Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl);
-
- /**
- * The context of the notification. This is the app context of the package posting the
- * notification.
- */
- private final Context mPackageContext;
-
- public MediaNotificationProcessor(Context context, Context packageContext) {
- this(context, packageContext, new ImageGradientColorizer());
- }
-
- @VisibleForTesting
- MediaNotificationProcessor(Context context, Context packageContext,
- ImageGradientColorizer colorizer) {
- mContext = context;
- mPackageContext = packageContext;
- mColorizer = colorizer;
- }
-
- /**
- * Processes a builder of a media notification and calculates the appropriate colors that should
- * be used.
- *
- * @param notification the notification that is being processed
- * @param builder the recovered builder for the notification. this will be modified
- */
- public void processNotification(Notification notification, Notification.Builder builder) {
- Icon largeIcon = notification.getLargeIcon();
- Bitmap bitmap = null;
- Drawable drawable = null;
- if (largeIcon != null) {
- // We're transforming the builder, let's make sure all baked in RemoteViews are
- // rebuilt!
- builder.setRebuildStyledRemoteViews(true);
- drawable = largeIcon.loadDrawable(mPackageContext);
- int backgroundColor = 0;
- if (notification.isColorizedMedia()) {
- int width = drawable.getIntrinsicWidth();
- int height = drawable.getIntrinsicHeight();
- int area = width * height;
- if (area > RESIZE_BITMAP_AREA) {
- double factor = Math.sqrt((float) RESIZE_BITMAP_AREA / area);
- width = (int) (factor * width);
- height = (int) (factor * height);
- }
- bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, width, height);
- drawable.draw(canvas);
-
- Palette.Builder paletteBuilder = generateArtworkPaletteBuilder(bitmap);
- Palette palette = paletteBuilder.generate();
- Palette.Swatch backgroundSwatch = findBackgroundSwatch(palette);
- backgroundColor = backgroundSwatch.getRgb();
- // we want most of the full region again, slightly shifted to the right
- float textColorStartWidthFraction = 0.4f;
- paletteBuilder.setRegion((int) (bitmap.getWidth() * textColorStartWidthFraction), 0,
- bitmap.getWidth(),
- bitmap.getHeight());
- // We're not filtering on white or black
- if (!isWhiteOrBlack(backgroundSwatch.getHsl())) {
- final float backgroundHue = backgroundSwatch.getHsl()[0];
- paletteBuilder.addFilter((rgb, hsl) -> {
- // at least 10 degrees hue difference
- float diff = Math.abs(hsl[0] - backgroundHue);
- return diff > 10 && diff < 350;
- });
- }
- paletteBuilder.addFilter(mBlackWhiteFilter);
- palette = paletteBuilder.generate();
- int foregroundColor = selectForegroundColor(backgroundColor, palette);
- builder.setColorPalette(backgroundColor, foregroundColor);
- } else {
- backgroundColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
- .getDefaultColor();
- }
- Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
- mContext.getResources().getConfiguration().getLayoutDirection() ==
- LayoutDirection.RTL);
- builder.setLargeIcon(Icon.createWithBitmap(colorized));
- }
- }
-
- /**
- * Select a foreground color depending on whether the background color is dark or light
- * @param backgroundColor Background color to coordinate with
- * @param palette Artwork palette, should be obtained from {@link generateArtworkPaletteBuilder}
- * @return foreground color
- */
- public static int selectForegroundColor(int backgroundColor, Palette palette) {
- if (ContrastColorUtil.isColorLight(backgroundColor)) {
- return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(),
- palette.getVibrantSwatch(),
- palette.getDarkMutedSwatch(),
- palette.getMutedSwatch(),
- palette.getDominantSwatch(),
- Color.BLACK);
- } else {
- return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(),
- palette.getVibrantSwatch(),
- palette.getLightMutedSwatch(),
- palette.getMutedSwatch(),
- palette.getDominantSwatch(),
- Color.WHITE);
- }
- }
-
- private static int selectForegroundColorForSwatches(Palette.Swatch moreVibrant,
- Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch,
- Palette.Swatch dominantSwatch, int fallbackColor) {
- Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant);
- if (coloredCandidate == null) {
- coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch);
- }
- if (coloredCandidate != null) {
- if (dominantSwatch == coloredCandidate) {
- return coloredCandidate.getRgb();
- } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation()
- < POPULATION_FRACTION_FOR_DOMINANT
- && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) {
- return dominantSwatch.getRgb();
- } else {
- return coloredCandidate.getRgb();
- }
- } else if (hasEnoughPopulation(dominantSwatch)) {
- return dominantSwatch.getRgb();
- } else {
- return fallbackColor;
- }
- }
-
- private static Palette.Swatch selectMutedCandidate(Palette.Swatch first,
- Palette.Swatch second) {
- boolean firstValid = hasEnoughPopulation(first);
- boolean secondValid = hasEnoughPopulation(second);
- if (firstValid && secondValid) {
- float firstSaturation = first.getHsl()[1];
- float secondSaturation = second.getHsl()[1];
- float populationFraction = first.getPopulation() / (float) second.getPopulation();
- if (firstSaturation * populationFraction > secondSaturation) {
- return first;
- } else {
- return second;
- }
- } else if (firstValid) {
- return first;
- } else if (secondValid) {
- return second;
- }
- return null;
- }
-
- private static Palette.Swatch selectVibrantCandidate(Palette.Swatch first,
- Palette.Swatch second) {
- boolean firstValid = hasEnoughPopulation(first);
- boolean secondValid = hasEnoughPopulation(second);
- if (firstValid && secondValid) {
- int firstPopulation = first.getPopulation();
- int secondPopulation = second.getPopulation();
- if (firstPopulation / (float) secondPopulation
- < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
- return second;
- } else {
- return first;
- }
- } else if (firstValid) {
- return first;
- } else if (secondValid) {
- return second;
- }
- return null;
- }
- private static boolean hasEnoughPopulation(Palette.Swatch swatch) {
- // We want a fraction that is at least 1% of the image
- return swatch != null
- && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION);
+ private MediaNotificationProcessor() {
}
/**
@@ -279,7 +72,7 @@ public class MediaNotificationProcessor {
List<Palette.Swatch> swatches = palette.getSwatches();
float highestNonWhitePopulation = -1;
Palette.Swatch second = null;
- for (Palette.Swatch swatch: swatches) {
+ for (Palette.Swatch swatch : swatches) {
if (swatch != dominantSwatch
&& swatch.getPopulation() > highestNonWhitePopulation
&& !isWhiteOrBlack(swatch.getHsl())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6cf5c303149c..815cfb39ea2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -668,7 +668,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
&& expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
boolean isMessagingLayout = contractedView instanceof MessagingLayout;
boolean isCallLayout = contractedView instanceof CallLayout;
- boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
if (customView && beforeS && !mIsSummaryWithChildren) {
if (beforeN) {
@@ -678,12 +677,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
smallHeight = mMaxSmallHeightBeforeS;
}
- } else if (isMediaLayout) {
- // TODO(b/172652345): MediaStyle notifications currently look broken when we enforce
- // the standard notification height, so we have to afford them more vertical space to
- // make sure we don't crop them terribly. We actually need to revisit this and give
- // them a headerless design, then remove this hack.
- smallHeight = showCompactMediaSeekbar ? mMaxSmallHeightMedia : mMaxSmallHeightBeforeS;
} else if (isMessagingLayout) {
// TODO(b/173204301): MessagingStyle notifications currently look broken when we enforce
// the standard notification height, so we have to afford them more vertical space to
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 58b87cd2f492..73c4b054fd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -40,13 +40,11 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.media.MediaDataManagerKt;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -799,13 +797,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder
// For all of our templates, we want it to be RTL
packageContext = new RtlEnabledContext(packageContext);
}
- Notification notification = sbn.getNotification();
- if (notification.isMediaNotification() && !(mIsMediaInQS
- && MediaDataManagerKt.isMediaNotification(sbn))) {
- MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
- packageContext);
- processor.processNotification(notification, recoveredBuilder);
- }
if (mEntry.getRanking().isConversation()) {
mConversationProcessor.processNotification(mEntry, recoveredBuilder);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 2535e5ddc3d1..c75cd782c3e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -16,341 +16,26 @@
package com.android.systemui.statusbar.notification.row.wrapper;
-import static com.android.systemui.Dependency.MAIN_HANDLER;
-
-import android.annotation.Nullable;
-import android.app.Notification;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewStub;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.widget.MediaNotificationView;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import java.util.Timer;
-import java.util.TimerTask;
-
/**
* Wraps a notification containing a media template
*/
public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
- private static final long PROGRESS_UPDATE_INTERVAL = 1000; // 1s
- private static final String COMPACT_MEDIA_TAG = "media";
- private final Handler mHandler = Dependency.get(MAIN_HANDLER);
- private Timer mSeekBarTimer;
private View mActions;
- private SeekBar mSeekBar;
- private TextView mSeekBarElapsedTime;
- private TextView mSeekBarTotalTime;
- private long mDuration = 0;
- private MediaController mMediaController;
- private MediaMetadata mMediaMetadata;
- private NotificationMediaManager mMediaManager;
- private View mSeekBarView;
- private Context mContext;
- private MetricsLogger mMetricsLogger;
- private boolean mIsViewVisible;
-
- @VisibleForTesting
- protected SeekBar.OnSeekBarChangeListener mSeekListener =
- new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- if (mMediaController != null) {
- mMediaController.getTransportControls().seekTo(mSeekBar.getProgress());
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_UPDATE));
- }
- }
- };
-
- private MediaNotificationView.VisibilityChangeListener mVisibilityListener =
- new MediaNotificationView.VisibilityChangeListener() {
- @Override
- public void onAggregatedVisibilityChanged(boolean isVisible) {
- mIsViewVisible = isVisible;
- if (isVisible && mMediaController != null) {
- // Restart timer if we're currently playing and didn't already have one going
- PlaybackState state = mMediaController.getPlaybackState();
- if (state != null && state.getState() == PlaybackState.STATE_PLAYING
- && mSeekBarTimer == null && mSeekBarView != null
- && mSeekBarView.getVisibility() != View.GONE) {
- startTimer();
- }
- } else {
- clearTimer();
- }
- }
- };
-
- private View.OnAttachStateChangeListener mAttachStateListener =
- new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- mIsViewVisible = false;
- }
- };
-
- private MediaController.Callback mMediaCallback = new MediaController.Callback() {
- @Override
- public void onSessionDestroyed() {
- clearTimer();
- mMediaController.unregisterCallback(this);
- if (mView instanceof MediaNotificationView) {
- ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
- mView.removeOnAttachStateChangeListener(mAttachStateListener);
- }
- }
-
- @Override
- public void onPlaybackStateChanged(@Nullable PlaybackState state) {
- if (state == null) {
- return;
- }
-
- if (state.getState() != PlaybackState.STATE_PLAYING) {
- // Update the UI once, in case playback info changed while we were paused
- updatePlaybackUi(state);
- clearTimer();
- } else if (mSeekBarTimer == null && mSeekBarView != null
- && mSeekBarView.getVisibility() != View.GONE) {
- startTimer();
- }
- }
-
- @Override
- public void onMetadataChanged(@Nullable MediaMetadata metadata) {
- if (mMediaMetadata == null || !mMediaMetadata.equals(metadata)) {
- mMediaMetadata = metadata;
- updateDuration();
- }
- }
- };
protected NotificationMediaTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
- mContext = ctx;
- mMediaManager = Dependency.get(NotificationMediaManager.class);
- mMetricsLogger = Dependency.get(MetricsLogger.class);
}
private void resolveViews() {
mActions = mView.findViewById(com.android.internal.R.id.media_actions);
- mIsViewVisible = mView.isShown();
-
- final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
- .getParcelable(Notification.EXTRA_MEDIA_SESSION);
-
- boolean showCompactSeekbar = mMediaManager.getShowCompactMediaSeekbar();
- if (token == null || (COMPACT_MEDIA_TAG.equals(mView.getTag()) && !showCompactSeekbar)) {
- if (mSeekBarView != null) {
- mSeekBarView.setVisibility(View.GONE);
- }
- return;
- }
-
- // Check for existing media controller and clean up / create as necessary
- boolean shouldUpdateListeners = false;
- if (mMediaController == null || !mMediaController.getSessionToken().equals(token)) {
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaCallback);
- }
- mMediaController = new MediaController(mContext, token);
- shouldUpdateListeners = true;
- }
-
- mMediaMetadata = mMediaController.getMetadata();
- if (mMediaMetadata != null) {
- long duration = mMediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- if (duration <= 0) {
- // Don't include the seekbar if this is a livestream
- if (mSeekBarView != null && mSeekBarView.getVisibility() != View.GONE) {
- mSeekBarView.setVisibility(View.GONE);
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
- clearTimer();
- } else if (mSeekBarView == null && shouldUpdateListeners) {
- // Only log if the controller changed, otherwise we would log multiple times for
- // the same notification when user pauses/resumes
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
- }
- return;
- } else if (mSeekBarView != null && mSeekBarView.getVisibility() == View.GONE) {
- // Otherwise, make sure the seekbar is visible
- mSeekBarView.setVisibility(View.VISIBLE);
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_OPEN));
- updateDuration();
- startTimer();
- }
- }
-
- // Inflate the seekbar template
- ViewStub stub = mView.findViewById(R.id.notification_media_seekbar_container);
- if (stub instanceof ViewStub) {
- LayoutInflater layoutInflater = LayoutInflater.from(stub.getContext());
- stub.setLayoutInflater(layoutInflater);
- stub.setLayoutResource(R.layout.notification_material_media_seekbar);
- mSeekBarView = stub.inflate();
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_OPEN));
-
- mSeekBar = mSeekBarView.findViewById(R.id.notification_media_progress_bar);
- mSeekBar.setOnSeekBarChangeListener(mSeekListener);
-
- mSeekBarElapsedTime = mSeekBarView.findViewById(R.id.notification_media_elapsed_time);
- mSeekBarTotalTime = mSeekBarView.findViewById(R.id.notification_media_total_time);
-
- shouldUpdateListeners = true;
- }
-
- if (shouldUpdateListeners) {
- if (mView instanceof MediaNotificationView) {
- MediaNotificationView mediaView = (MediaNotificationView) mView;
- mediaView.addVisibilityListener(mVisibilityListener);
- mView.addOnAttachStateChangeListener(mAttachStateListener);
- }
-
- if (mSeekBarTimer == null) {
- if (mMediaController != null && canSeekMedia(mMediaController.getPlaybackState())) {
- // Log initial state, since it will not be updated
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_DETAIL, 1));
- } else {
- setScrubberVisible(false);
- }
- updateDuration();
- startTimer();
- mMediaController.registerCallback(mMediaCallback);
- }
- }
- updateSeekBarTint(mSeekBarView);
- }
-
- private void startTimer() {
- clearTimer();
- if (mIsViewVisible) {
- mSeekBarTimer = new Timer(true /* isDaemon */);
- mSeekBarTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- mHandler.post(mOnUpdateTimerTick);
- }
- }, 0, PROGRESS_UPDATE_INTERVAL);
- }
- }
-
- private void clearTimer() {
- if (mSeekBarTimer != null) {
- mSeekBarTimer.cancel();
- mSeekBarTimer.purge();
- mSeekBarTimer = null;
- }
- }
-
- @Override
- public void setRemoved() {
- clearTimer();
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaCallback);
- }
- if (mView instanceof MediaNotificationView) {
- ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
- mView.removeOnAttachStateChangeListener(mAttachStateListener);
- }
- }
-
- private boolean canSeekMedia(@Nullable PlaybackState state) {
- if (state == null) {
- return false;
- }
-
- long actions = state.getActions();
- return ((actions & PlaybackState.ACTION_SEEK_TO) != 0);
- }
-
- private void setScrubberVisible(boolean isVisible) {
- if (mSeekBar == null || mSeekBar.isEnabled() == isVisible) {
- return;
- }
-
- mSeekBar.getThumb().setAlpha(isVisible ? 255 : 0);
- mSeekBar.setEnabled(isVisible);
- mMetricsLogger.write(newLog(MetricsEvent.TYPE_DETAIL, isVisible ? 1 : 0));
- }
-
- private void updateDuration() {
- if (mMediaMetadata != null && mSeekBar != null) {
- long duration = mMediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- if (mDuration != duration) {
- mDuration = duration;
- mSeekBar.setMax((int) mDuration);
- mSeekBarTotalTime.setText(millisecondsToTimeString(duration));
- }
- }
- }
-
- protected final Runnable mOnUpdateTimerTick = new Runnable() {
- @Override
- public void run() {
- if (mMediaController != null && mSeekBar != null) {
- PlaybackState playbackState = mMediaController.getPlaybackState();
- if (playbackState != null) {
- updatePlaybackUi(playbackState);
- } else {
- clearTimer();
- }
- } else {
- clearTimer();
- }
- }
- };
-
- private void updatePlaybackUi(PlaybackState state) {
- if (mSeekBar == null || mSeekBarElapsedTime == null) {
- return;
- }
-
- long position = state.getPosition();
- mSeekBar.setProgress((int) position);
-
- mSeekBarElapsedTime.setText(millisecondsToTimeString(position));
-
- // Update scrubber in case available actions have changed
- setScrubberVisible(canSeekMedia(state));
- }
-
- private String millisecondsToTimeString(long milliseconds) {
- long seconds = milliseconds / 1000;
- String text = DateUtils.formatElapsedTime(seconds);
- return text;
}
@Override
@@ -361,28 +46,6 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
super.onContentUpdated(row);
}
- private void updateSeekBarTint(View seekBarContainer) {
- if (seekBarContainer == null) {
- return;
- }
-
- if (this.getNotificationHeader() == null) {
- return;
- }
-
- int tintColor = getOriginalIconColor();
- mSeekBarElapsedTime.setTextColor(tintColor);
- mSeekBarTotalTime.setTextColor(tintColor);
- mSeekBarTotalTime.setShadowLayer(1.5f, 1.5f, 1.5f, mBackgroundColor);
-
- ColorStateList tintList = ColorStateList.valueOf(tintColor);
- mSeekBar.setThumbTintList(tintList);
- tintList = tintList.withAlpha(192); // 75%
- mSeekBar.setProgressTintList(tintList);
- tintList = tintList.withAlpha(128); // 50%
- mSeekBar.setProgressBackgroundTintList(tintList);
- }
-
@Override
protected void updateTransformedTypes() {
// This also clears the existing types
@@ -394,36 +57,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
}
@Override
- public boolean isDimmable() {
- return getCustomBackgroundColor() == 0;
- }
-
- @Override
public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
return true;
}
-
- /**
- * Returns an initialized LogMaker for logging changes to the seekbar
- * @return new LogMaker
- */
- private LogMaker newLog(int event) {
- String packageName = mRow.getEntry().getSbn().getPackageName();
-
- return new LogMaker(MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR)
- .setType(event)
- .setPackageName(packageName);
- }
-
- /**
- * Returns an initialized LogMaker for logging changes with subtypes
- * @return new LogMaker
- */
- private LogMaker newLog(int event, int subtype) {
- String packageName = mRow.getEntry().getSbn().getPackageName();
- return new LogMaker(MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR)
- .setType(event)
- .setSubtype(subtype)
- .setPackageName(packageName);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
index e6287e7063d3..aeb5b037be0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
@@ -18,31 +18,18 @@ package com.android.systemui.statusbar.notification;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertNotSame;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
import android.annotation.Nullable;
-import android.app.Notification;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.drawable.Drawable;
import android.test.suitebuilder.annotation.SmallTest;
-import android.widget.RemoteViews;
import androidx.palette.graphics.Palette;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.tests.R;
import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,17 +45,8 @@ public class MediaNotificationProcessorTest extends SysuiTestCase {
*/
private static final int COLOR_TOLERANCE = 8;
- private MediaNotificationProcessor mProcessor;
- private Bitmap mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- private ImageGradientColorizer mColorizer;
@Nullable private Bitmap mArtwork;
- @Before
- public void setUp() {
- mColorizer = spy(new TestableColorizer(mBitmap));
- mProcessor = new MediaNotificationProcessor(getContext(), getContext(), mColorizer);
- }
-
@After
public void tearDown() {
if (mArtwork != null) {
@@ -78,53 +56,6 @@ public class MediaNotificationProcessorTest extends SysuiTestCase {
}
@Test
- public void testColorizedWithLargeIcon() {
- Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
- R.drawable.ic_person)
- .setContentTitle("Title")
- .setLargeIcon(mBitmap)
- .setContentText("Text");
- Notification notification = builder.build();
- mProcessor.processNotification(notification, builder);
- verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
- }
-
- @Test
- public void testNotColorizedWithoutLargeIcon() {
- Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
- R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text");
- Notification notification = builder.build();
- mProcessor.processNotification(notification, builder);
- verifyZeroInteractions(mColorizer);
- }
-
- @Test
- public void testRemoteViewsReset() {
- Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
- R.drawable.ic_person)
- .setContentTitle("Title")
- .setStyle(new Notification.MediaStyle())
- .setLargeIcon(mBitmap)
- .setContentText("Text");
- Notification notification = builder.build();
- RemoteViews remoteViews = new RemoteViews(getContext().getPackageName(),
- R.layout.custom_view_dark);
- notification.contentView = remoteViews;
- notification.bigContentView = remoteViews;
- notification.headsUpContentView = remoteViews;
- mProcessor.processNotification(notification, builder);
- verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
- RemoteViews contentView = builder.createContentView();
- assertNotSame(contentView, remoteViews);
- contentView = builder.createBigContentView();
- assertNotSame(contentView, remoteViews);
- contentView = builder.createHeadsUpContentView();
- assertNotSame(contentView, remoteViews);
- }
-
- @Test
public void findBackgroundSwatch_white() {
// Given artwork that is completely white.
mArtwork = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
@@ -153,17 +84,4 @@ public class MediaNotificationProcessorTest extends SysuiTestCase {
assertThat((float) Color.green(expected)).isWithin(COLOR_TOLERANCE).of(Color.green(actual));
assertThat((float) Color.blue(expected)).isWithin(COLOR_TOLERANCE).of(Color.blue(actual));
}
-
- public static class TestableColorizer extends ImageGradientColorizer {
- private final Bitmap mBitmap;
-
- private TestableColorizer(Bitmap bitmap) {
- mBitmap = bitmap;
- }
-
- @Override
- public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
- return mBitmap;
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
deleted file mode 100644
index fbe4d7315baa..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.row.wrapper;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Notification;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.RemoteViews;
-import android.widget.SeekBar;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationMediaTemplateViewWrapperTest extends SysuiTestCase {
-
- private ExpandableNotificationRow mRow;
- private Notification mNotif;
- private View mView;
- private NotificationMediaTemplateViewWrapper mWrapper;
-
- @Mock
- private MetricsLogger mMetricsLogger;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- allowTestableLooperAsMainThread();
-
- mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
-
- // These tests are for regular media style notifications, not controls in quick settings
- Settings.System.putInt(mContext.getContentResolver(), "qs_media_player", 0);
- }
-
- private void makeTestNotification(long duration, boolean allowSeeking) throws Exception {
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text");
-
- MediaMetadata metadata = new MediaMetadata.Builder()
- .putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
- .build();
- MediaSession session = new MediaSession(mContext, "TEST_CHANNEL");
- session.setMetadata(metadata);
-
- PlaybackState playbackState = new PlaybackState.Builder()
- .setActions(allowSeeking ? PlaybackState.ACTION_SEEK_TO : 0)
- .build();
-
- session.setPlaybackState(playbackState);
-
- builder.setStyle(new Notification.MediaStyle()
- .setMediaSession(session.getSessionToken())
- );
-
- mNotif = builder.build();
- assertTrue(mNotif.hasMediaSession());
-
- NotificationTestHelper helper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
- mRow = helper.createRow(mNotif);
-
- RemoteViews views = new RemoteViews(mContext.getPackageName(),
- com.android.internal.R.layout.notification_template_material_big_media);
- mView = views.apply(mContext, null);
- mWrapper = new NotificationMediaTemplateViewWrapper(mContext,
- mView, mRow);
- mWrapper.onContentUpdated(mRow);
- }
-
- @Test
- public void testLogging_NoSeekbar() throws Exception {
- // Media sessions with duration <= 0 should not include a seekbar
- makeTestNotification(0, false);
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_CLOSE
- ));
-
- verify(mMetricsLogger, times(0)).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_OPEN
- ));
- }
-
- @Test
- public void testLogging_HasSeekbarNoScrubber() throws Exception {
- // Media sessions that do not support seeking should have a seekbar, but no scrubber
- makeTestNotification(1000, false);
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_OPEN
- ));
-
- // Ensure the callback runs at least once
- mWrapper.mOnUpdateTimerTick.run();
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_DETAIL
- && logMaker.getSubtype() == 0
- ));
- }
-
- @Test
- public void testLogging_HasSeekbarAndScrubber() throws Exception {
- makeTestNotification(1000, true);
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_OPEN
- ));
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_DETAIL
- && logMaker.getSubtype() == 1
- ));
- }
-
- @Test
- public void testLogging_UpdateSeekbar() throws Exception {
- makeTestNotification(1000, true);
-
- SeekBar seekbar = mView.findViewById(
- com.android.internal.R.id.notification_media_progress_bar);
- assertTrue(seekbar != null);
-
- mWrapper.mSeekListener.onStopTrackingTouch(seekbar);
-
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
- && logMaker.getType() == MetricsEvent.TYPE_UPDATE));
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index b9ffd65ee20e..a37d5c8a956a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -31,9 +31,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.media.session.MediaSession;
import android.os.Build;
-import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
@@ -73,7 +71,6 @@ public class NotificationComparatorTest extends UiServiceTestCase {
private NotificationRecord mRecordMinCallNonInterruptive;
private NotificationRecord mRecordMinCall;
private NotificationRecord mRecordHighCall;
- private NotificationRecord mRecordDefaultMedia;
private NotificationRecord mRecordEmail;
private NotificationRecord mRecordInlineReply;
private NotificationRecord mRecordSms;
@@ -139,15 +136,6 @@ public class NotificationComparatorTest extends UiServiceTestCase {
new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
- .setStyle(new Notification.MediaStyle()
- .setMediaSession(new MediaSession.Token(Process.myUid(), null)))
- .build();
- mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
- pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
- "", 1499), getDefaultChannel());
- mRecordDefaultMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
@@ -218,7 +206,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
.setStyle(new Notification.MediaStyle())
.build();
mNoMediaSessionMedia = new NotificationRecord(mContext, new StatusBarNotification(
- pkg2, pkg2, 1, "cheater", uid2, uid2, n12, new UserHandle(userId),
+ pkg2, pkg2, 1, "media", uid2, uid2, n12, new UserHandle(userId),
"", 9258), getDefaultChannel());
mNoMediaSessionMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
@@ -247,7 +235,6 @@ public class NotificationComparatorTest extends UiServiceTestCase {
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(mRecordColorizedCall);
expected.add(mRecordColorized);
- expected.add(mRecordDefaultMedia);
expected.add(mRecordHighCall);
expected.add(mRecordInlineReply);
if (mRecordSms != null) {