Use NotificationProgressDrawable for ProgressStyle notifications.
Also tint the indeterminate drawable with the color passed from the API.
Fixed a couple of bugs in NotificationProgressDrawable, caught by the
tests.
Flag: android.app.api_rich_ongoing
Bug: 367805202
Fix: 372907485
Test: post a ProgressStyle Notification
Test: patch ag/29675286 and run ProgressStyleNotificationScreenshotTest
Change-Id: I2449f755fa359278351986f17b8744f6e2bc5827
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index 3e597d7..d3b1f97 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -20,16 +20,20 @@
import android.annotation.Nullable;
import android.app.Notification.ProgressStyle;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.RemotableViewMethod;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
import androidx.annotation.ColorInt;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.NotificationProgressDrawable.Part;
@@ -49,7 +53,13 @@
*/
@RemoteViews.RemoteView
public class NotificationProgressBar extends ProgressBar {
+ private static final String TAG = "NotificationProgressBar";
+
private NotificationProgressModel mProgressModel;
+
+ @Nullable
+ private List<Part> mProgressDrawableParts = null;
+
@Nullable
private Drawable mProgressTrackerDrawable = null;
@@ -58,7 +68,7 @@
}
public NotificationProgressBar(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.progressBarStyle);
+ this(context, attrs, R.attr.progressBarStyle);
}
public NotificationProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -82,10 +92,42 @@
"Bundle shouldn't be null");
mProgressModel = NotificationProgressModel.fromBundle(bundle);
+
+ if (mProgressModel.isIndeterminate()) {
+ final int indeterminateColor = mProgressModel.getIndeterminateColor();
+ setIndeterminateTintList(ColorStateList.valueOf(indeterminateColor));
+ } else {
+ mProgressDrawableParts = processAndConvertToDrawableParts(mProgressModel.getSegments(),
+ mProgressModel.getPoints(),
+ mProgressModel.getProgress(), mProgressModel.isStyledByProgress());
+
+ try {
+ final NotificationProgressDrawable drawable = getNotificationProgressDrawable();
+ drawable.setParts(mProgressDrawableParts);
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "Can't set parts because can't get NotificationProgressDrawable", ex);
+ }
+ }
}
- private void setProgressModel(@NonNull NotificationProgressModel model) {
- mProgressModel = model;
+ @NonNull
+ private NotificationProgressDrawable getNotificationProgressDrawable() {
+ final Drawable d = getProgressDrawable();
+ if (d == null) {
+ throw new IllegalStateException("getProgressDrawable() returns null");
+ }
+ if (!(d instanceof LayerDrawable)) {
+ throw new IllegalStateException("getProgressDrawable() doesn't return a LayerDrawable");
+ }
+
+ final Drawable layer = ((LayerDrawable) d).findDrawableByLayerId(R.id.background);
+ if (!(layer instanceof NotificationProgressDrawable)) {
+ throw new IllegalStateException(
+ "Couldn't get NotificationProgressDrawable, retrieved drawable is: " + (
+ layer != null ? layer.toString() : null));
+ }
+
+ return (NotificationProgressDrawable) layer;
}
/**
@@ -97,7 +139,6 @@
public void setProgressTrackerIcon(@Nullable Icon icon) {
}
-
/**
* Async version of {@link #setProgressTrackerIcon}
*/
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
index 89ef875..2be7273 100644
--- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -45,6 +45,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -156,11 +157,18 @@
}
/**
- *
+ * Set the segments and points that constitute the drawable.
+ */
+ public void setParts(List<Part> parts) {
+ mParts.clear();
+ mParts.addAll(parts);
+ }
+
+ /**
+ * Set the segments and points that constitute the drawable.
*/
public void setParts(@NonNull Part... parts) {
- mParts.clear();
- mParts.addAll(Arrays.asList(parts));
+ setParts(Arrays.asList(parts));
}
@Override
@@ -379,7 +387,7 @@
if (state.mThemeAttrsPoints != null) {
final TypedArray a = t.resolveAttributes(
state.mThemeAttrsPoints, R.styleable.NotificationProgressDrawablePoints);
- updateSegmentsFromTypedArray(a);
+ updatePointsFromTypedArray(a);
a.recycle();
}
}
@@ -651,9 +659,11 @@
State(@NonNull State orig, @Nullable Resources res) {
mChangingConfigurations = orig.mChangingConfigurations;
+ mSegSegGap = orig.mSegSegGap;
+ mSegPointGap = orig.mSegPointGap;
+ mStrokeWidth = orig.mStrokeWidth;
mStrokeColor = orig.mStrokeColor;
mFadedStrokeColor = orig.mFadedStrokeColor;
- mStrokeWidth = orig.mStrokeWidth;
mStrokeDashWidth = orig.mStrokeDashWidth;
mStrokeDashGap = orig.mStrokeDashGap;
mPointRadius = orig.mPointRadius;
@@ -791,6 +801,7 @@
final State state = mState;
mStrokePaint.setStrokeWidth(state.mStrokeWidth);
+ mDashedStrokePaint.setStrokeWidth(state.mStrokeWidth);
if (state.mStrokeDashWidth != 0.0f) {
final DashPathEffect e = new DashPathEffect(
diff --git a/core/res/res/drawable/notification_progress.xml b/core/res/res/drawable/notification_progress.xml
new file mode 100644
index 0000000..3a6b600
--- /dev/null
+++ b/core/res/res/drawable/notification_progress.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@id/background"
+ android:gravity="center_vertical|fill_horizontal">
+ <com.android.internal.widget.NotificationProgressDrawable
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:segSegGap="@dimen/notification_progress_segSeg_gap"
+ android:segPointGap="@dimen/notification_progress_segPoint_gap">
+ <segments
+ android:color="?attr/colorProgressBackgroundNormal"
+ android:dashGap="@dimen/notification_progress_segments_dash_gap"
+ android:dashWidth="@dimen/notification_progress_segments_dash_width"
+ android:width="@dimen/notification_progress_segments_height" />
+ <points
+ android:color="?attr/colorProgressBackgroundNormal"
+ android:radius="@dimen/notification_progress_points_radius"
+ android:cornerRadius="@dimen/notification_progress_points_corner_radius"
+ android:inset="@dimen/notification_progress_points_inset" />
+ </com.android.internal.widget.NotificationProgressDrawable>
+ </item>
+</layer-list>
diff --git a/core/res/res/layout/notification_template_material_progress.xml b/core/res/res/layout/notification_template_material_progress.xml
index fdcefcc..75827a2 100644
--- a/core/res/res/layout/notification_template_material_progress.xml
+++ b/core/res/res/layout/notification_template_material_progress.xml
@@ -75,12 +75,11 @@
/>
- <com.android.internal.widget.NotificationProgressBar
- android:id="@+id/progress"
+ <include
android:layout_width="0dp"
- android:layout_height="@dimen/notification_progress_bar_height"
- style="@style/Widget.Material.Light.ProgressBar.Horizontal"
android:layout_weight="1"
+ android:layout_height="@dimen/notification_progress_tracker_height"
+ layout="@layout/notification_template_notification_progress_bar"
/>
<com.android.internal.widget.CachingIconView
diff --git a/core/res/res/layout/notification_template_notification_progress_bar.xml b/core/res/res/layout/notification_template_notification_progress_bar.xml
new file mode 100644
index 0000000..3574896
--- /dev/null
+++ b/core/res/res/layout/notification_template_notification_progress_bar.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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
+ -->
+
+<com.android.internal.widget.NotificationProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_progress_tracker_height"
+ style="@style/Widget.Material.Notification.NotificationProgressBar"
+ />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b92aa2f..7184d9a 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -817,6 +817,22 @@
<dimen name="notification_progress_tracker_width">40dp</dimen>
<!-- The size of the progress tracker height -->
<dimen name="notification_progress_tracker_height">20dp</dimen>
+ <!-- The gap between segments in the notification progress bar -->
+ <dimen name="notification_progress_segSeg_gap">2dp</dimen>
+ <!-- The gap between a segment and a point in the notification progress bar -->
+ <dimen name="notification_progress_segPoint_gap">4dp</dimen>
+ <!-- The dash gap of the notification progress bar segments -->
+ <dimen name="notification_progress_segments_dash_gap">9dp</dimen>
+ <!-- The dash width of the notification progress bar segments -->
+ <dimen name="notification_progress_segments_dash_width">3dp</dimen>
+ <!-- The height of the notification progress bar segments -->
+ <dimen name="notification_progress_segments_height">6dp</dimen>
+ <!-- The radius of the notification progress bar points -->
+ <dimen name="notification_progress_points_radius">10dp</dimen>
+ <!-- The corner radius of the notification progress bar points drawn as rects -->
+ <dimen name="notification_progress_points_corner_radius">4dp</dimen>
+ <!-- The inset of the notification progress bar points drawn as rects -->
+ <dimen name="notification_progress_points_inset">0dp</dimen>
<!-- The maximum size of the small notification icon on low memory devices. -->
<dimen name="notification_small_icon_size_low_ram">@dimen/notification_small_icon_size</dimen>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index eec6ae3..cb8e4aa 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -502,6 +502,10 @@
<style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
+ <style name="Widget.Material.Notification.NotificationProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal">
+ <item name="progressDrawable">@drawable/notification_progress</item>
+ </style>
+
<style name="Widget.Material.Notification.Text" parent="Widget.Material.Light.TextView">
<item name="lineHeight">20sp</item>
<item name="textAppearance">@style/TextAppearance.Material.Notification</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4f63fac..12b444b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3864,6 +3864,14 @@
<java-symbol type="dimen" name="notification_progress_icon_size" />
<java-symbol type="dimen" name="notification_progress_tracker_width" />
<java-symbol type="dimen" name="notification_progress_tracker_height" />
+ <java-symbol type="dimen" name="notification_progress_segSeg_gap" />
+ <java-symbol type="dimen" name="notification_progress_segPoint_gap" />
+ <java-symbol type="dimen" name="notification_progress_segments_dash_gap" />
+ <java-symbol type="dimen" name="notification_progress_segments_dash_width" />
+ <java-symbol type="dimen" name="notification_progress_segments_height" />
+ <java-symbol type="dimen" name="notification_progress_points_radius" />
+ <java-symbol type="dimen" name="notification_progress_points_corner_radius" />
+ <java-symbol type="dimen" name="notification_progress_points_inset" />
<java-symbol type="dimen" name="notification_small_icon_size_low_ram"/>
<java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
index 6419c1e0..79a478a 100644
--- a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
@@ -254,7 +254,6 @@
// Colors with 50% opacity
int fadedGreen = 0x7F00FF00;
- int fadedBlue = 0x7F0000FF;
int fadedYellow = 0x7FFFFF00;
List<Part> expected = new ArrayList<>(List.of(