diff options
| author | 2025-01-15 18:47:32 +0000 | |
|---|---|---|
| committer | 2025-01-16 22:34:32 +0000 | |
| commit | 5bb5a9cca2c96b14cf6acf371e4990948f1e8b8e (patch) | |
| tree | 0225cce13b55fa381f9dfc5f6da6af7b64d4b28b | |
| parent | 21ea15303ae01f7a10a13cc1fba3d7e2c3dd9ae8 (diff) | |
Implement fallbacks for when the drawable doesn't have enough width.
Also:
- For better clarity, renamed `processAndConvertToViewParts` to
`processModelAndConvertToViewParts`, and
`processAndConvertToDrawableParts` to
`processPartsAndConvertToDrawableParts`.
- Fixed pre-existing failures in NotificationProgressModelTest. And a
few tests were failing the verifs on process or indeterminateColor.
- Cleaned up / reassigned a couple of TODOs.
Test notification config, on Felix:
- 10 segments, each of length 10
- Case 1: segments of multiple colors
- Case 2: segments of same color
- 4 points, at 0, 1, 55, 100
Flag: android.app.api_rich_ongoing
Fix: 372908709
Bug: 390196782
Test: Post ProgressStyle notifs via test app
Test: atest NotificationProgressBarTest
Test: atest NotificationProgressModelTest
Change-Id: I57333e2c14058298b5caf707442176883162b345
6 files changed, 556 insertions, 121 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 93d751cb9402..fbe5b9449b00 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -11854,7 +11854,7 @@ public class Notification implements Parcelable // If segment limit is exceeded. All segments will be replaced // with a single segment boolean allSameColor = true; - int firstSegmentColor = segments.get(0).getColor(); + int firstSegmentColor = segments.getFirst().getColor(); for (int i = 1; i < segments.size(); i++) { if (segments.get(i).getColor() != firstSegmentColor) { @@ -11887,8 +11887,31 @@ public class Notification implements Parcelable } } + // If the segments and points can't all fit inside the progress drawable, the + // view will replace all segments with a single segment. + final int segmentsFallbackColor; + if (segments.size() <= 1) { + segmentsFallbackColor = NotificationProgressModel.INVALID_COLOR; + } else { + + boolean allSameColor = true; + int firstSegmentColor = segments.getFirst().getColor(); + for (int i = 1; i < segments.size(); i++) { + if (segments.get(i).getColor() != firstSegmentColor) { + allSameColor = false; + break; + } + } + // If the segments are of the same color, the view can just use that color. + // In that case there is no need to send the fallback color. + segmentsFallbackColor = allSameColor ? NotificationProgressModel.INVALID_COLOR + : sanitizeProgressColor(Notification.COLOR_DEFAULT, backgroundColor, + defaultProgressColor); + } + model = new NotificationProgressModel(segments, points, - Math.clamp(mProgress, 0, totalLength), mIsStyledByProgress); + Math.clamp(mProgress, 0, totalLength), mIsStyledByProgress, + segmentsFallbackColor); } return model; } diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java index 0d3c470b0e8a..973fd7ecf38b 100644 --- a/core/java/com/android/internal/widget/NotificationProgressBar.java +++ b/core/java/com/android/internal/widget/NotificationProgressBar.java @@ -47,6 +47,7 @@ import com.android.internal.widget.NotificationProgressDrawable.DrawablePoint; import com.android.internal.widget.NotificationProgressDrawable.DrawableSegment; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -161,7 +162,7 @@ public final class NotificationProgressBar extends ProgressBar implements final int progress = mProgressModel.getProgress(); final int progressMax = mProgressModel.getProgressMax(); - mParts = processAndConvertToViewParts(mProgressModel.getSegments(), + mParts = processModelAndConvertToViewParts(mProgressModel.getSegments(), mProgressModel.getPoints(), progress, progressMax); @@ -439,23 +440,107 @@ public final class NotificationProgressBar extends ProgressBar implements return; } - mProgressDrawableParts = processAndConvertToDrawableParts( + final float segSegGap = mNotificationProgressDrawable.getSegSegGap(); + final float segPointGap = mNotificationProgressDrawable.getSegPointGap(); + final float pointRadius = mNotificationProgressDrawable.getPointRadius(); + mProgressDrawableParts = processPartsAndConvertToDrawableParts( mParts, width, - mNotificationProgressDrawable.getSegSegGap(), - mNotificationProgressDrawable.getSegPointGap(), - mNotificationProgressDrawable.getPointRadius(), + segSegGap, + segPointGap, + pointRadius, mHasTrackerIcon ); - Pair<List<DrawablePart>, Float> p = maybeStretchAndRescaleSegments( - mParts, - mProgressDrawableParts, - mNotificationProgressDrawable.getSegmentMinWidth(), - mNotificationProgressDrawable.getPointRadius(), - getProgressFraction(), - width, - mProgressModel.isStyledByProgress(), - mHasTrackerIcon ? 0F : mNotificationProgressDrawable.getSegSegGap()); + + final float segmentMinWidth = mNotificationProgressDrawable.getSegmentMinWidth(); + final float progressFraction = getProgressFraction(); + final boolean isStyledByProgress = mProgressModel.isStyledByProgress(); + final float progressGap = + mHasTrackerIcon ? 0F : mNotificationProgressDrawable.getSegSegGap(); + Pair<List<DrawablePart>, Float> p = null; + try { + p = maybeStretchAndRescaleSegments( + mParts, + mProgressDrawableParts, + segmentMinWidth, + pointRadius, + progressFraction, + width, + isStyledByProgress, + progressGap + ); + } catch (NotEnoughWidthToFitAllPartsException ex) { + Log.w(TAG, "Failed to stretch and rescale segments", ex); + } + + List<ProgressStyle.Segment> fallbackSegments = null; + if (p == null && mProgressModel.getSegments().size() > 1) { + Log.w(TAG, "Falling back to single segment"); + try { + fallbackSegments = List.of(new ProgressStyle.Segment(getMax()).setColor( + mProgressModel.getSegmentsFallbackColor() + == NotificationProgressModel.INVALID_COLOR + ? mProgressModel.getSegments().getFirst().getColor() + : mProgressModel.getSegmentsFallbackColor())); + p = processModelAndConvertToFinalDrawableParts( + fallbackSegments, + mProgressModel.getPoints(), + mProgressModel.getProgress(), + getMax(), + width, + segSegGap, + segPointGap, + pointRadius, + mHasTrackerIcon, + segmentMinWidth, + isStyledByProgress + ); + } catch (NotEnoughWidthToFitAllPartsException ex) { + Log.w(TAG, "Failed to stretch and rescale segments with single segment fallback", + ex); + } + } + + if (p == null && !mProgressModel.getPoints().isEmpty()) { + Log.w(TAG, "Falling back to single segment and no points"); + if (fallbackSegments == null) { + fallbackSegments = List.of(new ProgressStyle.Segment(getMax()).setColor( + mProgressModel.getSegmentsFallbackColor() + == NotificationProgressModel.INVALID_COLOR + ? mProgressModel.getSegments().getFirst().getColor() + : mProgressModel.getSegmentsFallbackColor())); + } + try { + p = processModelAndConvertToFinalDrawableParts( + fallbackSegments, + Collections.emptyList(), + mProgressModel.getProgress(), + getMax(), + width, + segSegGap, + segPointGap, + pointRadius, + mHasTrackerIcon, + segmentMinWidth, + isStyledByProgress + ); + } catch (NotEnoughWidthToFitAllPartsException ex) { + Log.w(TAG, + "Failed to stretch and rescale segments with single segments and no points", + ex); + } + } + + if (p == null) { + Log.w(TAG, "Falling back to no stretching and rescaling"); + p = maybeSplitDrawableSegmentsByProgress( + mParts, + mProgressDrawableParts, + progressFraction, + width, + isStyledByProgress, + progressGap); + } if (DEBUG) { Log.d(TAG, "Updating NotificationProgressDrawable parts"); @@ -502,7 +587,11 @@ public final class NotificationProgressBar extends ProgressBar implements int min = getMin(); int max = getMax(); int range = max - min; - return range > 0 ? (getProgress() - min) / (float) range : 0; + return getProgressFraction(range, (getProgress() - min)); + } + + private static float getProgressFraction(int progressMax, int progress) { + return progressMax > 0 ? progress / (float) progressMax : 0; } /** @@ -636,7 +725,7 @@ public final class NotificationProgressBar extends ProgressBar implements * Processes the ProgressStyle data and convert to a list of {@code Part}. */ @VisibleForTesting - public static List<Part> processAndConvertToViewParts( + public static List<Part> processModelAndConvertToViewParts( List<ProgressStyle.Segment> segments, List<ProgressStyle.Point> points, int progress, @@ -796,7 +885,7 @@ public final class NotificationProgressBar extends ProgressBar implements * Processes the list of {@code Part} and convert to a list of {@code DrawablePart}. */ @VisibleForTesting - public static List<DrawablePart> processAndConvertToDrawableParts( + public static List<DrawablePart> processPartsAndConvertToDrawableParts( List<Part> parts, float totalWidth, float segSegGap, @@ -823,7 +912,7 @@ public final class NotificationProgressBar extends ProgressBar implements // Retract the end position to account for the padding and a point immediately // after. final float endOffset = getSegEndOffset(segment, nextPart, pointRadius, segPointGap, - segSegGap, iPart == nParts - 2, totalWidth, hasTrackerIcon); + segSegGap, iPart == nParts - 2, hasTrackerIcon); final float end = x + segWidth - endOffset; drawableParts.add(new DrawableSegment(start, end, segment.mColor, segment.mFaded)); @@ -864,7 +953,7 @@ public final class NotificationProgressBar extends ProgressBar implements } private static float getSegEndOffset(Segment seg, Part nextPart, float pointRadius, - float segPointGap, float segSegGap, boolean isSecondToLastPart, float totalWidth, + float segPointGap, float segSegGap, boolean isSecondToLastPart, boolean hasTrackerIcon) { if (nextPart == null) return 0F; if (nextPart instanceof Segment nextSeg) { @@ -894,7 +983,7 @@ public final class NotificationProgressBar extends ProgressBar implements float totalWidth, boolean isStyledByProgress, float progressGap - ) { + ) throws NotEnoughWidthToFitAllPartsException { final List<DrawableSegment> drawableSegments = drawableParts .stream() .filter(DrawableSegment.class::isInstance) @@ -920,16 +1009,8 @@ public final class NotificationProgressBar extends ProgressBar implements } if (totalExcessWidth < 0) { - // TODO: b/372908709 - throw an error so that the caller can catch and go to fallback - // option. (instead of return.) - Log.w(TAG, "Not enough width to satisfy the minimum width for segments."); - return maybeSplitDrawableSegmentsByProgress( - parts, - drawableParts, - progressFraction, - totalWidth, - isStyledByProgress, - progressGap); + throw new NotEnoughWidthToFitAllPartsException( + "Not enough width to satisfy the minimum width for segments."); } final int nParts = drawableParts.size(); @@ -1003,8 +1084,7 @@ public final class NotificationProgressBar extends ProgressBar implements final int nParts = parts.size(); for (int iPart = 0; iPart < nParts; iPart++) { final Part part = parts.get(iPart); - if (!(part instanceof Segment)) continue; - final Segment segment = (Segment) part; + if (!(part instanceof Segment segment)) continue; if (startFraction == progressFraction) { iPartFirstSegmentToStyle = iPart; rescaledProgressX = segment.mStart; @@ -1066,11 +1146,37 @@ public final class NotificationProgressBar extends ProgressBar implements } /** + * Processes the ProgressStyle data and convert to a pair of: + * - list of processed {@code DrawablePart}. + * - location of progress on the stretched and rescaled progress bar. + */ + @VisibleForTesting + public static Pair<List<DrawablePart>, Float> processModelAndConvertToFinalDrawableParts( + List<ProgressStyle.Segment> segments, + List<ProgressStyle.Point> points, + int progress, + int progressMax, + float totalWidth, + float segSegGap, + float segPointGap, + float pointRadius, + boolean hasTrackerIcon, + float segmentMinWidth, + boolean isStyledByProgress + ) throws NotEnoughWidthToFitAllPartsException { + List<Part> parts = processModelAndConvertToViewParts(segments, points, progress, + progressMax); + List<DrawablePart> drawableParts = processPartsAndConvertToDrawableParts(parts, totalWidth, + segSegGap, segPointGap, pointRadius, hasTrackerIcon); + return maybeStretchAndRescaleSegments(parts, drawableParts, segmentMinWidth, pointRadius, + getProgressFraction(progressMax, progress), totalWidth, isStyledByProgress, + hasTrackerIcon ? 0F : segSegGap); + } + + /** * A part of the progress bar, which is either a {@link Segment} with non-zero length, or a * {@link Point} with zero length. */ - // TODO: b/372908709 - maybe this should be made private? Only test the final - // NotificationDrawable.Parts. public interface Part { } @@ -1176,4 +1282,10 @@ public final class NotificationProgressBar extends ProgressBar implements return Objects.hash(mColor); } } + + public static class NotEnoughWidthToFitAllPartsException extends Exception { + public NotEnoughWidthToFitAllPartsException(String message) { + super(message); + } + } } diff --git a/core/java/com/android/internal/widget/NotificationProgressModel.java b/core/java/com/android/internal/widget/NotificationProgressModel.java index e8cb37e8f19b..7eaf861f2af4 100644 --- a/core/java/com/android/internal/widget/NotificationProgressModel.java +++ b/core/java/com/android/internal/widget/NotificationProgressModel.java @@ -16,7 +16,6 @@ package com.android.internal.widget; - import android.annotation.ColorInt; import android.annotation.FlaggedApi; import android.annotation.NonNull; @@ -45,24 +44,29 @@ import java.util.Objects; */ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) public final class NotificationProgressModel { - private static final int INVALID_INDETERMINATE_COLOR = Color.TRANSPARENT; + public static final int INVALID_COLOR = Color.TRANSPARENT; private static final String KEY_SEGMENTS = "segments"; private static final String KEY_POINTS = "points"; private static final String KEY_PROGRESS = "progress"; private static final String KEY_IS_STYLED_BY_PROGRESS = "isStyledByProgress"; + private static final String KEY_SEGMENTS_FALLBACK_COLOR = "segmentsFallColor"; private static final String KEY_INDETERMINATE_COLOR = "indeterminateColor"; private final List<Segment> mSegments; private final List<Point> mPoints; private final int mProgress; private final boolean mIsStyledByProgress; @ColorInt + private final int mSegmentsFallbackColor; + + @ColorInt private final int mIndeterminateColor; public NotificationProgressModel( @NonNull List<Segment> segments, @NonNull List<Point> points, int progress, - boolean isStyledByProgress + boolean isStyledByProgress, + @ColorInt int segmentsFallbackColor ) { Preconditions.checkArgument(progress >= 0); Preconditions.checkArgument(!segments.isEmpty()); @@ -70,17 +74,19 @@ public final class NotificationProgressModel { mPoints = points; mProgress = progress; mIsStyledByProgress = isStyledByProgress; - mIndeterminateColor = INVALID_INDETERMINATE_COLOR; + mSegmentsFallbackColor = segmentsFallbackColor; + mIndeterminateColor = INVALID_COLOR; } public NotificationProgressModel( @ColorInt int indeterminateColor ) { - Preconditions.checkArgument(indeterminateColor != INVALID_INDETERMINATE_COLOR); + Preconditions.checkArgument(indeterminateColor != INVALID_COLOR); mSegments = Collections.emptyList(); mPoints = Collections.emptyList(); mProgress = 0; mIsStyledByProgress = false; + mSegmentsFallbackColor = INVALID_COLOR; mIndeterminateColor = indeterminateColor; } @@ -105,12 +111,17 @@ public final class NotificationProgressModel { } @ColorInt + public int getSegmentsFallbackColor() { + return mSegmentsFallbackColor; + } + + @ColorInt public int getIndeterminateColor() { return mIndeterminateColor; } public boolean isIndeterminate() { - return mIndeterminateColor != INVALID_INDETERMINATE_COLOR; + return mIndeterminateColor != INVALID_COLOR; } /** @@ -119,7 +130,7 @@ public final class NotificationProgressModel { @NonNull public Bundle toBundle() { final Bundle bundle = new Bundle(); - if (mIndeterminateColor != INVALID_INDETERMINATE_COLOR) { + if (mIndeterminateColor != INVALID_COLOR) { bundle.putInt(KEY_INDETERMINATE_COLOR, mIndeterminateColor); } else { bundle.putParcelableList(KEY_SEGMENTS, @@ -128,6 +139,9 @@ public final class NotificationProgressModel { Notification.ProgressStyle.getProgressPointsAsBundleList(mPoints)); bundle.putInt(KEY_PROGRESS, mProgress); bundle.putBoolean(KEY_IS_STYLED_BY_PROGRESS, mIsStyledByProgress); + if (mSegmentsFallbackColor != INVALID_COLOR) { + bundle.putInt(KEY_SEGMENTS_FALLBACK_COLOR, mSegmentsFallbackColor); + } } return bundle; } @@ -138,8 +152,8 @@ public final class NotificationProgressModel { @NonNull public static NotificationProgressModel fromBundle(@NonNull Bundle bundle) { final int indeterminateColor = bundle.getInt(KEY_INDETERMINATE_COLOR, - INVALID_INDETERMINATE_COLOR); - if (indeterminateColor != INVALID_INDETERMINATE_COLOR) { + INVALID_COLOR); + if (indeterminateColor != INVALID_COLOR) { return new NotificationProgressModel(indeterminateColor); } else { final List<Segment> segments = @@ -150,7 +164,10 @@ public final class NotificationProgressModel { bundle.getParcelableArrayList(KEY_POINTS, Bundle.class)); final int progress = bundle.getInt(KEY_PROGRESS); final boolean isStyledByProgress = bundle.getBoolean(KEY_IS_STYLED_BY_PROGRESS); - return new NotificationProgressModel(segments, points, progress, isStyledByProgress); + final int segmentsFallbackColor = bundle.getInt(KEY_SEGMENTS_FALLBACK_COLOR, + INVALID_COLOR); + return new NotificationProgressModel(segments, points, progress, isStyledByProgress, + segmentsFallbackColor); } } @@ -161,6 +178,7 @@ public final class NotificationProgressModel { + ", mPoints=" + mPoints + ", mProgress=" + mProgress + ", mIsStyledByProgress=" + mIsStyledByProgress + + ", mSegmentsFallbackColor=" + mSegmentsFallbackColor + ", mIndeterminateColor=" + mIndeterminateColor + "}"; } @@ -171,6 +189,7 @@ public final class NotificationProgressModel { final NotificationProgressModel that = (NotificationProgressModel) o; return mProgress == that.mProgress && mIsStyledByProgress == that.mIsStyledByProgress + && mSegmentsFallbackColor == that.mSegmentsFallbackColor && mIndeterminateColor == that.mIndeterminateColor && Objects.equals(mSegments, that.mSegments) && Objects.equals(mPoints, that.mPoints); @@ -182,6 +201,7 @@ public final class NotificationProgressModel { mPoints, mProgress, mIsStyledByProgress, + mSegmentsFallbackColor, mIndeterminateColor); } } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index bd1d3033165e..a1f85c380a95 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7585,7 +7585,7 @@ <!-- Used to config the segments of a NotificationProgressDrawable. --> <!-- @hide internal use only --> <declare-styleable name="NotificationProgressDrawableSegments"> - <!-- TODO: b/372908709 - maybe move this to NotificationProgressBar, because that's the only + <!-- TODO: b/390196782 - maybe move this to NotificationProgressBar, because that's the only place this is used actually. Same for NotificationProgressDrawable.segSegGap/segPointGap above. --> <!-- Minimum required drawing width. The drawing width refers to the width after 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 9818e19cea02..ec19c0c52759 100644 --- a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java @@ -16,6 +16,8 @@ package com.android.internal.widget; +import static com.android.internal.widget.NotificationProgressBar.NotEnoughWidthToFitAllPartsException; + import static com.google.common.truth.Truth.assertThat; import android.app.Notification.ProgressStyle; @@ -35,6 +37,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @RunWith(AndroidJUnit4.class) @@ -47,7 +50,7 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -60,7 +63,7 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -73,7 +76,7 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -86,7 +89,7 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -98,20 +101,21 @@ public class NotificationProgressBarTest { int progress = -50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @Test - public void processAndConvertToParts_progressIsZero() { + public void processAndConvertToParts_progressIsZero() + throws NotificationProgressBar.NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(100).setColor(Color.RED)); List<ProgressStyle.Point> points = new ArrayList<>(); int progress = 0; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>(List.of(new Segment(1f, Color.RED))); @@ -123,8 +127,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 300, Color.RED))); @@ -148,15 +153,16 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_progressAtMax() { + public void processAndConvertToParts_progressAtMax() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(100).setColor(Color.RED)); List<ProgressStyle.Point> points = new ArrayList<>(); int progress = 100; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>(List.of(new Segment(1f, Color.RED))); @@ -168,8 +174,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 300, Color.RED))); @@ -195,7 +202,7 @@ public class NotificationProgressBarTest { int progress = 150; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -208,7 +215,7 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @@ -221,12 +228,62 @@ public class NotificationProgressBarTest { int progress = 50; int progressMax = 100; - NotificationProgressBar.processAndConvertToViewParts(segments, points, progress, + NotificationProgressBar.processModelAndConvertToViewParts(segments, points, progress, progressMax); } @Test - public void processAndConvertToParts_multipleSegmentsWithoutPoints() { + public void processAndConvertToParts_singleSegmentWithoutPoints() + throws NotEnoughWidthToFitAllPartsException { + List<ProgressStyle.Segment> segments = new ArrayList<>(); + segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); + List<ProgressStyle.Point> points = new ArrayList<>(); + int progress = 60; + int progressMax = 100; + + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); + + List<Part> expectedParts = new ArrayList<>( + List.of(new Segment(1, Color.BLUE))); + + assertThat(parts).isEqualTo(expectedParts); + + float drawableWidth = 300; + float segSegGap = 4; + float segPointGap = 4; + float pointRadius = 6; + boolean hasTrackerIcon = true; + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + List<DrawablePart> expectedDrawableParts = new ArrayList<>( + List.of(new DrawableSegment(0, 300, Color.BLUE))); + + assertThat(drawableParts).isEqualTo(expectedDrawableParts); + + float segmentMinWidth = 16; + boolean isStyledByProgress = true; + + Pair<List<DrawablePart>, Float> p = NotificationProgressBar.maybeStretchAndRescaleSegments( + parts, drawableParts, segmentMinWidth, pointRadius, (float) progress / progressMax, + 300, isStyledByProgress, hasTrackerIcon ? 0 : segSegGap); + + // Colors with 40% opacity + int fadedBlue = 0x660000FF; + expectedDrawableParts = new ArrayList<>( + List.of(new DrawableSegment(0, 180, Color.BLUE), + new DrawableSegment(180, 300, fadedBlue, true))); + + assertThat(p.second).isEqualTo(180); + assertThat(p.first).isEqualTo(expectedDrawableParts); + } + + @Test + public void processAndConvertToParts_multipleSegmentsWithoutPoints() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); @@ -234,8 +291,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.50f, Color.RED), new Segment(0.50f, Color.GREEN))); @@ -248,8 +305,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 146, Color.RED), @@ -274,15 +332,16 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_multipleSegmentsWithoutPoints_noTracker() { + public void processAndConvertToParts_multipleSegmentsWithoutPoints_noTracker() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); List<ProgressStyle.Point> points = new ArrayList<>(); int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.50f, Color.RED), new Segment(0.50f, Color.GREEN))); @@ -295,8 +354,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = false; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 146, Color.RED), @@ -321,7 +381,8 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_singleSegmentWithPoints() { + public void processAndConvertToParts_singleSegmentWithPoints() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); List<ProgressStyle.Point> points = new ArrayList<>(); @@ -332,8 +393,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.15f, Color.BLUE), @@ -354,8 +415,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 35, Color.BLUE), @@ -396,7 +458,8 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_multipleSegmentsWithPoints() { + public void processAndConvertToParts_multipleSegmentsWithPoints() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); @@ -408,8 +471,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.15f, Color.RED), @@ -430,8 +493,9 @@ public class NotificationProgressBarTest { float segPointGap = 4; float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 35, Color.RED), new DrawablePoint(39, 51, Color.RED), @@ -473,7 +537,8 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_multipleSegmentsWithPointsAtStartAndEnd() { + public void processAndConvertToParts_multipleSegmentsWithPointsAtStartAndEnd() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); @@ -485,8 +550,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Point(Color.RED), @@ -505,8 +570,10 @@ public class NotificationProgressBarTest { float segPointGap = 4; float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawablePoint(0, 12, Color.RED), @@ -547,7 +614,8 @@ public class NotificationProgressBarTest { // The points are so close to start/end that they would go out of bounds without the minimum // segment width requirement. @Test - public void processAndConvertToParts_multipleSegmentsWithPointsNearStartAndEnd() { + public void processAndConvertToParts_multipleSegmentsWithPointsNearStartAndEnd() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); @@ -559,8 +627,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.01f, Color.RED), @@ -581,8 +649,10 @@ public class NotificationProgressBarTest { float segPointGap = 4; float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, -7, Color.RED), @@ -625,7 +695,8 @@ public class NotificationProgressBarTest { } @Test - public void processAndConvertToParts_multipleSegmentsWithPoints_notStyledByProgress() { + public void processAndConvertToParts_multipleSegmentsWithPoints_notStyledByProgress() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(50).setColor(Color.RED)); segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN)); @@ -636,8 +707,8 @@ public class NotificationProgressBarTest { int progress = 60; int progressMax = 100; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Segment(0.15f, Color.RED), new Point(Color.RED), @@ -653,8 +724,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawableSegment(0, 35, Color.RED), new DrawablePoint(39, 51, Color.RED), @@ -691,7 +763,8 @@ public class NotificationProgressBarTest { // The only difference from the `zeroWidthDrawableSegment` test below is the longer // segmentMinWidth (= 16dp). @Test - public void maybeStretchAndRescaleSegments_negativeWidthDrawableSegment() { + public void maybeStretchAndRescaleSegments_negativeWidthDrawableSegment() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); segments.add(new ProgressStyle.Segment(200).setColor(Color.BLUE)); @@ -702,8 +775,8 @@ public class NotificationProgressBarTest { int progress = 1000; int progressMax = 1000; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Point(Color.BLUE), new Segment(0.1f, Color.BLUE), @@ -717,8 +790,10 @@ public class NotificationProgressBarTest { float segPointGap = 4; float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawablePoint(0, 12, Color.BLUE), @@ -749,7 +824,8 @@ public class NotificationProgressBarTest { // The only difference from the `negativeWidthDrawableSegment` test above is the shorter // segmentMinWidth (= 10dp). @Test - public void maybeStretchAndRescaleSegments_zeroWidthDrawableSegment() { + public void maybeStretchAndRescaleSegments_zeroWidthDrawableSegment() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); segments.add(new ProgressStyle.Segment(200).setColor(Color.BLUE)); @@ -760,8 +836,8 @@ public class NotificationProgressBarTest { int progress = 1000; int progressMax = 1000; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Point(Color.BLUE), new Segment(0.1f, Color.BLUE), @@ -775,8 +851,10 @@ public class NotificationProgressBarTest { float segPointGap = 4; float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawablePoint(0, 12, Color.BLUE), @@ -805,7 +883,8 @@ public class NotificationProgressBarTest { } @Test - public void maybeStretchAndRescaleSegments_noStretchingNecessary() { + public void maybeStretchAndRescaleSegments_noStretchingNecessary() + throws NotEnoughWidthToFitAllPartsException { List<ProgressStyle.Segment> segments = new ArrayList<>(); segments.add(new ProgressStyle.Segment(200).setColor(Color.BLUE)); segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); @@ -816,8 +895,8 @@ public class NotificationProgressBarTest { int progress = 1000; int progressMax = 1000; - List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points, - progress, progressMax); + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); List<Part> expectedParts = new ArrayList<>( List.of(new Point(Color.BLUE), new Segment(0.2f, Color.BLUE), @@ -832,8 +911,9 @@ public class NotificationProgressBarTest { float pointRadius = 6; boolean hasTrackerIcon = true; - List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts( - parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); List<DrawablePart> expectedDrawableParts = new ArrayList<>( List.of(new DrawablePoint(0, 12, Color.BLUE), @@ -854,4 +934,168 @@ public class NotificationProgressBarTest { assertThat(p.second).isEqualTo(200); assertThat(p.first).isEqualTo(expectedDrawableParts); } + + @Test(expected = NotEnoughWidthToFitAllPartsException.class) + public void maybeStretchAndRescaleSegments_notEnoughWidthToFitAllParts() + throws NotEnoughWidthToFitAllPartsException { + final int orange = 0xff7f50; + List<ProgressStyle.Segment> segments = new ArrayList<>(); + segments.add(new ProgressStyle.Segment(10).setColor(orange)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.YELLOW)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.BLUE)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.GREEN)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.RED)); + segments.add(new ProgressStyle.Segment(10).setColor(orange)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.YELLOW)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.BLUE)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.GREEN)); + segments.add(new ProgressStyle.Segment(10).setColor(Color.RED)); + List<ProgressStyle.Point> points = new ArrayList<>(); + points.add(new ProgressStyle.Point(0).setColor(orange)); + points.add(new ProgressStyle.Point(1).setColor(Color.BLUE)); + points.add(new ProgressStyle.Point(55).setColor(Color.BLUE)); + points.add(new ProgressStyle.Point(100).setColor(orange)); + int progress = 50; + int progressMax = 100; + + List<Part> parts = NotificationProgressBar.processModelAndConvertToViewParts(segments, + points, progress, progressMax); + + List<Part> expectedParts = new ArrayList<>( + List.of(new Point(orange), + new Segment(0.01f, orange), + new Point(Color.BLUE), + new Segment(0.09f, orange), + new Segment(0.1f, Color.YELLOW), + new Segment(0.1f, Color.BLUE), + new Segment(0.1f, Color.GREEN), + new Segment(0.1f, Color.RED), + new Segment(0.05f, orange), + new Point(Color.BLUE), + new Segment(0.05f, orange), + new Segment(0.1f, Color.YELLOW), + new Segment(0.1f, Color.BLUE), + new Segment(0.1f, Color.GREEN), + new Segment(0.1f, Color.RED), + new Point(orange))); + + assertThat(parts).isEqualTo(expectedParts); + + // For the list of ProgressStyle.Part used in this test, 300 is the minimum width. + float drawableWidth = 299; + float segSegGap = 4; + float segPointGap = 4; + float pointRadius = 6; + boolean hasTrackerIcon = true; + + List<DrawablePart> drawableParts = + NotificationProgressBar.processPartsAndConvertToDrawableParts( + parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon); + + // Skips the validation of the intermediate list of DrawableParts. + + float segmentMinWidth = 16; + boolean isStyledByProgress = true; + + NotificationProgressBar.maybeStretchAndRescaleSegments( + parts, drawableParts, segmentMinWidth, pointRadius, (float) progress / progressMax, + 300, isStyledByProgress, hasTrackerIcon ? 0 : segSegGap); + } + + @Test + public void processModelAndConvertToFinalDrawableParts_singleSegmentWithPoints() + throws NotEnoughWidthToFitAllPartsException { + List<ProgressStyle.Segment> segments = new ArrayList<>(); + segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); + List<ProgressStyle.Point> points = new ArrayList<>(); + points.add(new ProgressStyle.Point(15).setColor(Color.RED)); + points.add(new ProgressStyle.Point(25).setColor(Color.BLUE)); + points.add(new ProgressStyle.Point(60).setColor(Color.BLUE)); + points.add(new ProgressStyle.Point(75).setColor(Color.YELLOW)); + int progress = 60; + int progressMax = 100; + + float drawableWidth = 300; + float segSegGap = 4; + float segPointGap = 4; + float pointRadius = 6; + boolean hasTrackerIcon = true; + + float segmentMinWidth = 16; + boolean isStyledByProgress = true; + + Pair<List<DrawablePart>, Float> p = + NotificationProgressBar.processModelAndConvertToFinalDrawableParts( + segments, + points, + progress, + progressMax, + drawableWidth, + segSegGap, + segPointGap, + pointRadius, + hasTrackerIcon, + segmentMinWidth, + isStyledByProgress + ); + + // Colors with 40% opacity + int fadedBlue = 0x660000FF; + int fadedYellow = 0x66FFFF00; + List<DrawablePart> expectedDrawableParts = new ArrayList<>( + List.of(new DrawableSegment(0, 34.219177F, Color.BLUE), + new DrawablePoint(38.219177F, 50.219177F, Color.RED), + new DrawableSegment(54.219177F, 70.21918F, Color.BLUE), + new DrawablePoint(74.21918F, 86.21918F, Color.BLUE), + new DrawableSegment(90.21918F, 172.38356F, Color.BLUE), + new DrawablePoint(176.38356F, 188.38356F, Color.BLUE), + new DrawableSegment(192.38356F, 217.0137F, fadedBlue, true), + new DrawablePoint(221.0137F, 233.0137F, fadedYellow), + new DrawableSegment(237.0137F, 300F, fadedBlue, true))); + + assertThat(p.second).isEqualTo(182.38356F); + assertThat(p.first).isEqualTo(expectedDrawableParts); + } + + @Test + public void processModelAndConvertToFinalDrawableParts_singleSegmentWithoutPoints() + throws NotEnoughWidthToFitAllPartsException { + List<ProgressStyle.Segment> segments = new ArrayList<>(); + segments.add(new ProgressStyle.Segment(100).setColor(Color.BLUE)); + int progress = 60; + int progressMax = 100; + + float drawableWidth = 100; + float segSegGap = 4; + float segPointGap = 4; + float pointRadius = 6; + boolean hasTrackerIcon = true; + + float segmentMinWidth = 16; + boolean isStyledByProgress = true; + + Pair<List<DrawablePart>, Float> p = + NotificationProgressBar.processModelAndConvertToFinalDrawableParts( + segments, + Collections.emptyList(), + progress, + progressMax, + drawableWidth, + segSegGap, + segPointGap, + pointRadius, + hasTrackerIcon, + segmentMinWidth, + isStyledByProgress + ); + + // Colors with 40% opacity + int fadedBlue = 0x660000FF; + List<DrawablePart> expectedDrawableParts = new ArrayList<>( + List.of(new DrawableSegment(0, 60.000004F, Color.BLUE), + new DrawableSegment(60.000004F, 100, fadedBlue, true))); + + assertThat(p.second).isWithin(1e-5f).of(60); + assertThat(p.first).isEqualTo(expectedDrawableParts); + } } diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java index 962399e48fb8..e1f5b1c2e4a4 100644 --- a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressModelTest.java @@ -49,7 +49,8 @@ public class NotificationProgressModelTest { new NotificationProgressModel(List.of(), List.of(), 10, - false); + false, + Color.TRANSPARENT); } @Test(expected = IllegalArgumentException.class) @@ -58,7 +59,8 @@ public class NotificationProgressModelTest { List.of(new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW)), List.of(), -1, - false); + false, + Color.TRANSPARENT); } @Test @@ -74,14 +76,15 @@ public class NotificationProgressModelTest { // THEN assertThat(restoredModel.getIndeterminateColor()).isEqualTo(Color.RED); assertThat(restoredModel.isIndeterminate()).isTrue(); - assertThat(restoredModel.getProgress()).isEqualTo(-1); + assertThat(restoredModel.getProgress()).isEqualTo(0); assertThat(restoredModel.getSegments()).isEmpty(); assertThat(restoredModel.getPoints()).isEmpty(); assertThat(restoredModel.isStyledByProgress()).isFalse(); + assertThat(restoredModel.getSegmentsFallbackColor()).isEqualTo(Color.TRANSPARENT); } @Test - public void save_and_restore_non_indeterminate_progress_model() { + public void save_and_restore_determinate_progress_model() { // GIVEN final List<Notification.ProgressStyle.Segment> segments = List.of( new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW), @@ -92,7 +95,8 @@ public class NotificationProgressModelTest { final NotificationProgressModel savedModel = new NotificationProgressModel(segments, points, 100, - true); + true, + Color.RED); final Bundle bundle = savedModel.toBundle(); @@ -106,6 +110,38 @@ public class NotificationProgressModelTest { assertThat(restoredModel.getPoints()).isEqualTo(points); assertThat(restoredModel.getProgress()).isEqualTo(100); assertThat(restoredModel.isStyledByProgress()).isTrue(); - assertThat(restoredModel.getIndeterminateColor()).isEqualTo(-1); + assertThat(restoredModel.getSegmentsFallbackColor()).isEqualTo(Color.RED); + assertThat(restoredModel.getIndeterminateColor()).isEqualTo(Color.TRANSPARENT); + } + + @Test + public void save_and_restore_non_determinate_progress_model_segments_fallback_color_invalid() { + // GIVEN + final List<Notification.ProgressStyle.Segment> segments = List.of( + new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW), + new Notification.ProgressStyle.Segment(50).setColor(Color.YELLOW)); + final List<Notification.ProgressStyle.Point> points = List.of( + new Notification.ProgressStyle.Point(0).setColor(Color.RED), + new Notification.ProgressStyle.Point(20).setColor(Color.BLUE)); + final NotificationProgressModel savedModel = new NotificationProgressModel(segments, + points, + 100, + true, + Color.TRANSPARENT); + + final Bundle bundle = savedModel.toBundle(); + + // WHEN + final NotificationProgressModel restoredModel = + NotificationProgressModel.fromBundle(bundle); + + // THEN + assertThat(restoredModel.isIndeterminate()).isFalse(); + assertThat(restoredModel.getSegments()).isEqualTo(segments); + assertThat(restoredModel.getPoints()).isEqualTo(points); + assertThat(restoredModel.getProgress()).isEqualTo(100); + assertThat(restoredModel.isStyledByProgress()).isTrue(); + assertThat(restoredModel.getSegmentsFallbackColor()).isEqualTo(Color.TRANSPARENT); + assertThat(restoredModel.getIndeterminateColor()).isEqualTo(Color.TRANSPARENT); } } |