diff options
7 files changed, 443 insertions, 33 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt index 1a1af2eecc00..87abd0a4494a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt @@ -1,5 +1,6 @@ package com.android.systemui.statusbar.notification.stack +import android.platform.test.annotations.EnableFlags import android.service.notification.StatusBarNotification import android.testing.TestableLooper.RunWithLooper import android.view.LayoutInflater @@ -20,6 +21,7 @@ import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView +import com.android.systemui.statusbar.notification.shared.NotificationMinimalism import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState import com.android.systemui.util.mockito.mock import junit.framework.Assert.assertEquals @@ -30,6 +32,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.mock +import org.mockito.Mockito.spy import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -59,7 +62,7 @@ open class NotificationShelfTest : SysuiTestCase() { .inflate( /* resource = */ R.layout.status_bar_notification_shelf, /* root = */ root, - /* attachToRoot = */ false + /* attachToRoot = */ false, ) as NotificationShelf whenever(ambientState.largeScreenShadeInterpolator).thenReturn(largeScreenShadeInterpolator) @@ -128,6 +131,177 @@ open class NotificationShelfTest : SysuiTestCase() { } @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testAlignment_splitShade_LTR() { + // Given: LTR mode, split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40) + + // Then: shelf should align to end + assertTrue(shelfSpy.isAlignedToEnd) + assertTrue(shelfSpy.isAlignedToRight) + assertTrue(shelfSpy.mBackgroundNormal.alignToEnd) + assertTrue(shelfSpy.mShelfIcons.alignToEnd) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testAlignment_nonSplitShade_LTR() { + // Given: LTR mode, non split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40) + + // Then: shelf should not align to end + assertFalse(shelfSpy.isAlignedToEnd) + assertFalse(shelfSpy.isAlignedToRight) + assertFalse(shelfSpy.mBackgroundNormal.alignToEnd) + assertFalse(shelfSpy.mShelfIcons.alignToEnd) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testAlignment_splitShade_RTL() { + // Given: RTL mode, split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40) + + // Then: shelf should align to end, but to left due to RTL + assertTrue(shelfSpy.isAlignedToEnd) + assertFalse(shelfSpy.isAlignedToRight) + assertTrue(shelfSpy.mBackgroundNormal.alignToEnd) + assertTrue(shelfSpy.mShelfIcons.alignToEnd) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testAlignment_nonSplitShade_RTL() { + // Given: RTL mode, non split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40) + + // Then: shelf should not align to end, but to right due to RTL + assertFalse(shelfSpy.isAlignedToEnd) + assertTrue(shelfSpy.isAlignedToRight) + assertFalse(shelfSpy.mBackgroundNormal.alignToEnd) + assertFalse(shelfSpy.mShelfIcons.alignToEnd) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfLeftBound_splitShade_LTR() { + // Given: LTR mode, split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40) + + // When: get the left bound of the shelf + val shelfLeftBound = shelfSpy.shelfLeftBound + + // Then: should be equal to shelf's width - actual width + assertEquals(60f, shelfLeftBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfRightBound_splitShade_LTR() { + // Given: LTR mode, split shade, width 100, actual width 40 + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40) + + // Then: the right bound of the shelf should be equal to shelf's width + assertEquals(100f, shelfSpy.shelfRightBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfLeftBound_nonSplitShade_LTR() { + // Given: LTR mode, non split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40) + + // When: get the left bound of the shelf + val shelfLeftBound = shelfSpy.shelfLeftBound + + // Then: should be equal to 0f + assertEquals(0f, shelfLeftBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfRightBound_nonSplitShade_LTR() { + // Given: LTR mode, non split shade, width 100, actual width 40 + val shelfSpy = + prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40) + + // Then: the right bound of the shelf should be equal to shelf's actual width + assertEquals(40f, shelfSpy.shelfRightBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfLeftBound_splitShade_RTL() { + // Given: RTL mode, split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40) + + // When: get the left bound of the shelf + val shelfLeftBound = shelfSpy.shelfLeftBound + + // Then: should be equal to 0f + assertEquals(0f, shelfLeftBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfRightBound_splitShade_RTL() { + // Given: RTL mode, split shade, width 100, actual width 40 + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40) + + // Then: the right bound of the shelf should be equal to shelf's actual width + assertEquals(40f, shelfSpy.shelfRightBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfLeftBound_nonSplitShade_RTL() { + // Given: RTL mode, non split shade + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40) + + // When: get the left bound of the shelf + val shelfLeftBound = shelfSpy.shelfLeftBound + + // Then: should be equal to shelf's width - actual width + assertEquals(60f, shelfLeftBound) + } + + @Test + @EnableFlags(NotificationMinimalism.FLAG_NAME) + fun testGetShelfRightBound_nonSplitShade_RTL() { + // Given: LTR mode, non split shade, width 100, actual width 40 + val shelfSpy = + prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40) + + // Then: the right bound of the shelf should be equal to shelf's width + assertEquals(100f, shelfSpy.shelfRightBound) + } + + private fun prepareShelfSpy( + shelf: NotificationShelf, + rtl: Boolean, + splitShade: Boolean, + width: Int, + actualWidth: Int, + ): NotificationShelf { + val shelfSpy = spy(shelf) + whenever(shelfSpy.isLayoutRtl).thenReturn(rtl) + whenever(ambientState.useSplitShade).thenReturn(splitShade) + whenever(shelfSpy.width).thenReturn(width) + shelfSpy.setActualWidth(actualWidth.toFloat()) + return shelfSpy + } + + @Test fun getAmountInShelf_lastViewBelowShelf_completelyInShelf() { val shelfClipStart = 0f val viewStart = 1f @@ -152,7 +326,7 @@ open class NotificationShelfTest : SysuiTestCase() { /* scrollingFast= */ false, /* expandingAnimated= */ false, /* isLastChild= */ true, - shelfClipStart + shelfClipStart, ) assertEquals(1f, amountInShelf) } @@ -182,7 +356,7 @@ open class NotificationShelfTest : SysuiTestCase() { /* scrollingFast= */ false, /* expandingAnimated= */ false, /* isLastChild= */ true, - shelfClipStart + shelfClipStart, ) assertEquals(1f, amountInShelf) } @@ -212,7 +386,7 @@ open class NotificationShelfTest : SysuiTestCase() { /* scrollingFast= */ false, /* expandingAnimated= */ false, /* isLastChild= */ true, - shelfClipStart + shelfClipStart, ) assertEquals(0.5f, amountInShelf) } @@ -241,7 +415,7 @@ open class NotificationShelfTest : SysuiTestCase() { /* scrollingFast= */ false, /* expandingAnimated= */ false, /* isLastChild= */ true, - shelfClipStart + shelfClipStart, ) assertEquals(0f, amountInShelf) } @@ -250,7 +424,7 @@ open class NotificationShelfTest : SysuiTestCase() { fun updateState_expansionChanging_shelfTransparent() { updateState_expansionChanging_shelfAlphaUpdated( expansionFraction = 0.25f, - expectedAlpha = 0.0f + expectedAlpha = 0.0f, ) } @@ -260,7 +434,7 @@ open class NotificationShelfTest : SysuiTestCase() { updateState_expansionChanging_shelfAlphaUpdated( expansionFraction = 0.85f, - expectedAlpha = 0.0f + expectedAlpha = 0.0f, ) } @@ -281,7 +455,7 @@ open class NotificationShelfTest : SysuiTestCase() { updateState_expansionChanging_shelfAlphaUpdated( expansionFraction = expansionFraction, - expectedAlpha = 0.123f + expectedAlpha = 0.123f, ) } @@ -330,7 +504,7 @@ open class NotificationShelfTest : SysuiTestCase() { /* scrollingFast= */ false, /* expandingAnimated= */ false, /* isLastChild= */ true, - shelfClipStart + shelfClipStart, ) assertEquals(1f, amountInShelf) } @@ -628,7 +802,7 @@ open class NotificationShelfTest : SysuiTestCase() { private fun updateState_expansionChanging_shelfAlphaUpdated( expansionFraction: Float, - expectedAlpha: Float + expectedAlpha: Float, ) { val sbnMock: StatusBarNotification = mock() val mockEntry = mock<NotificationEntry>().apply { whenever(this.sbn).thenReturn(sbnMock) } diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml index 58c545036b27..071b07631ff9 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml @@ -24,11 +24,11 @@ android:clickable="true" > - <com.android.systemui.statusbar.notification.row.NotificationBackgroundView + <com.android.systemui.statusbar.notification.shelf.NotificationShelfBackgroundView android:id="@+id/backgroundNormal" android:layout_width="match_parent" android:layout_height="match_parent" /> - <com.android.systemui.statusbar.phone.NotificationIconContainer + <com.android.systemui.statusbar.notification.shelf.NotificationShelfIconContainer android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index d523bc1867c2..48cf7a83c324 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -48,6 +48,9 @@ import com.android.systemui.statusbar.notification.SourceType; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.shared.NotificationMinimalism; +import com.android.systemui.statusbar.notification.shelf.NotificationShelfBackgroundView; +import com.android.systemui.statusbar.notification.shelf.NotificationShelfIconContainer; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; @@ -76,7 +79,11 @@ public class NotificationShelf extends ActivatableNotificationView { private static final SourceType BASE_VALUE = SourceType.from("BaseValue"); private static final SourceType SHELF_SCROLL = SourceType.from("ShelfScroll"); - private NotificationIconContainer mShelfIcons; + @VisibleForTesting + public NotificationShelfIconContainer mShelfIcons; + // This field hides mBackgroundNormal from super class for short-shelf alignment + @VisibleForTesting + public NotificationShelfBackgroundView mBackgroundNormal; private boolean mHideBackground; private int mStatusBarHeight; private boolean mEnableNotificationClipping; @@ -116,6 +123,8 @@ public class NotificationShelf extends ActivatableNotificationView { mShelfIcons.setClipChildren(false); mShelfIcons.setClipToPadding(false); + mBackgroundNormal = (NotificationShelfBackgroundView) super.mBackgroundNormal; + setClipToActualHeight(false); setClipChildren(false); setClipToPadding(false); @@ -268,19 +277,37 @@ public class NotificationShelf extends ActivatableNotificationView { } } - private void setActualWidth(float actualWidth) { + /** + * Set the actual width of the shelf, this will only differ from width for short shelves. + */ + @VisibleForTesting + public void setActualWidth(float actualWidth) { setBackgroundWidth((int) actualWidth); if (mShelfIcons != null) { + mShelfIcons.setAlignToEnd(isAlignedToEnd()); mShelfIcons.setActualLayoutWidth((int) actualWidth); } mActualWidth = actualWidth; } @Override + public void setBackgroundWidth(int width) { + super.setBackgroundWidth(width); + if (!NotificationMinimalism.isEnabled()) { + return; + } + if (mBackgroundNormal != null) { + mBackgroundNormal.setAlignToEnd(isAlignedToEnd()); + } + } + + @Override public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { super.getBoundsOnScreen(outRect, clipToParent); final int actualWidth = getActualWidth(); - if (isLayoutRtl()) { + final boolean alignedToRight = NotificationMinimalism.isEnabled() ? isAlignedToRight() : + isLayoutRtl(); + if (alignedToRight) { outRect.left = outRect.right - actualWidth; } else { outRect.right = outRect.left + actualWidth; @@ -326,11 +353,17 @@ public class NotificationShelf extends ActivatableNotificationView { */ @Override public boolean pointInView(float localX, float localY, float slop) { - final float containerWidth = getWidth(); - final float shelfWidth = getActualWidth(); + final float left, right; - final float left = isLayoutRtl() ? containerWidth - shelfWidth : 0; - final float right = isLayoutRtl() ? containerWidth : shelfWidth; + if (NotificationMinimalism.isEnabled()) { + left = getShelfLeftBound(); + right = getShelfRightBound(); + } else { + final float containerWidth = getWidth(); + final float shelfWidth = getActualWidth(); + left = isLayoutRtl() ? containerWidth - shelfWidth : 0; + right = isLayoutRtl() ? containerWidth : shelfWidth; + } final float top = mClipTopAmount; final float bottom = getActualHeight(); @@ -339,10 +372,53 @@ public class NotificationShelf extends ActivatableNotificationView { && isYInView(localY, slop, top, bottom); } + /** + * @return The left boundary of the shelf. + */ + @VisibleForTesting + public float getShelfLeftBound() { + if (isAlignedToRight()) { + return getWidth() - getActualWidth(); + } else { + return 0; + } + } + + /** + * @return The right boundary of the shelf. + */ + @VisibleForTesting + public float getShelfRightBound() { + if (isAlignedToRight()) { + return getWidth(); + } else { + return getActualWidth(); + } + } + + @VisibleForTesting + public boolean isAlignedToRight() { + return isAlignedToEnd() ^ isLayoutRtl(); + } + + /** + * When notification minimalism is on, on split shade, we want the notification shelf to align + * to the layout end (right for LTR; left for RTL). + * @return whether to align with the minimalism split shade style + */ + @VisibleForTesting + public boolean isAlignedToEnd() { + if (!NotificationMinimalism.isEnabled()) { + return false; + } + return mAmbientState.getUseSplitShade(); + } + @Override public void updateBackgroundColors() { super.updateBackgroundColors(); ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance(); + if (colorUpdateLogger != null) { colorUpdateLogger.logEvent("Shelf.updateBackgroundColors()", "normalBgColor=" + hexColorString(getNormalBgColor()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index e440d2728263..dd3a9c9dcf21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -169,12 +169,12 @@ public class NotificationBackgroundView extends View implements Dumpable, && !mExpandAnimationRunning) { bottom -= mClipBottomAmount; } - final boolean isRtl = isLayoutRtl(); + final boolean alignedToRight = isAlignedToRight(); final int width = getWidth(); final int actualWidth = getActualWidth(); - int left = isRtl ? width - actualWidth : 0; - int right = isRtl ? width : actualWidth; + int left = alignedToRight ? width - actualWidth : 0; + int right = alignedToRight ? width : actualWidth; if (mExpandAnimationRunning) { // Horizontally center this background view inside of the container @@ -185,6 +185,15 @@ public class NotificationBackgroundView extends View implements Dumpable, return new Rect(left, top, right, bottom); } + /** + * @return Whether the background view should be right-aligned. This only matters if the + * actualWidth is different than the full (measured) width. In other words, this is used to + * define the short-shelf alignment. + */ + protected boolean isAlignedToRight() { + return isLayoutRtl(); + } + private void draw(Canvas canvas, Drawable drawable) { NotificationAddXOnHoverToDismiss.assertInLegacyMode(); @@ -196,12 +205,13 @@ public class NotificationBackgroundView extends View implements Dumpable, && !mExpandAnimationRunning) { bottom -= mClipBottomAmount; } - final boolean isRtl = isLayoutRtl(); + + final boolean alignedToRight = isAlignedToRight(); final int width = getWidth(); final int actualWidth = getActualWidth(); - int left = isRtl ? width - actualWidth : 0; - int right = isRtl ? width : actualWidth; + int left = alignedToRight ? width - actualWidth : 0; + int right = alignedToRight ? width : actualWidth; if (mExpandAnimationRunning) { // Horizontally center this background view inside of the container diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfBackgroundView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfBackgroundView.kt new file mode 100644 index 000000000000..d7eea0190e2e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfBackgroundView.kt @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package com.android.systemui.statusbar.notification.shelf + +import android.content.Context +import android.util.AttributeSet +import androidx.annotation.VisibleForTesting +import com.android.systemui.statusbar.notification.row.NotificationBackgroundView +import com.android.systemui.statusbar.notification.shared.NotificationMinimalism + +/** The background view for the NotificationShelf. */ +class NotificationShelfBackgroundView +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null) : + NotificationBackgroundView(context, attrs) { + + /** Whether the notification shelf is aligned to end, need to keep persistent with the shelf. */ + var alignToEnd = false + + /** @return whether the alignment of the notification shelf is right. */ + @VisibleForTesting + public override fun isAlignedToRight(): Boolean { + if (!NotificationMinimalism.isEnabled) { + return super.isAlignedToRight() + } + return alignToEnd xor isLayoutRtl + } + + override fun toDumpString(): String { + return super.toDumpString() + " alignToEnd=" + alignToEnd + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt new file mode 100644 index 000000000000..64d165402759 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package com.android.systemui.statusbar.notification.shelf + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import com.android.systemui.statusbar.notification.shared.NotificationMinimalism +import com.android.systemui.statusbar.phone.NotificationIconContainer +import kotlin.math.max + +/** The NotificationIconContainer for the NotificationShelf. */ +class NotificationShelfIconContainer +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null) : + NotificationIconContainer(context, attrs) { + + /** Whether the notification shelf is aligned to end. */ + var alignToEnd = false + + /** + * @return The left boundary (not the RTL compatible start) of the area that icons can be added. + */ + override fun getLeftBound(): Float { + if (!NotificationMinimalism.isEnabled) { + return super.getLeftBound() + } + + if (isAlignedToRight) { + return (max(width - actualWidth, 0) + actualPaddingStart) + } + return actualPaddingStart + } + + /** + * @return The right boundary (not the RTL compatible end) of the area that icons can be added. + */ + override fun getRightBound(): Float { + if (!NotificationMinimalism.isEnabled) { + return super.getRightBound() + } + + if (isAlignedToRight) { + return width - actualPaddingEnd + } + return actualWidth - actualPaddingEnd + } + + /** + * For RTL, the icons' x positions should be mirrored around the middle of the shelf so that the + * icons are also added to the shelf from right to left. This function should only be called + * when RTL. + */ + override fun getRtlIconTranslationX(iconState: IconState, iconView: View): Float { + if (!NotificationMinimalism.isEnabled) { + return super.getRtlIconTranslationX(iconState, iconView) + } + + if (!isLayoutRtl) { + return iconState.xTranslation + } + + if (isAlignedToRight) { + return width * 2 - actualWidth - iconState.xTranslation - iconView.width + } + return actualWidth - iconState.xTranslation - iconView.width + } + + private val isAlignedToRight: Boolean + get() { + if (!NotificationMinimalism.isEnabled) { + return isLayoutRtl + } + return alignToEnd xor isLayoutRtl + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index ecd62bd6943b..c396512ce3a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -198,7 +198,7 @@ public class NotificationIconContainer extends ViewGroup { Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); - canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint); + canvas.drawRect(getActualPaddingStart(), 0, getRightBound(), getHeight(), paint); if (DEBUG_OVERFLOW) { if (mLastVisibleIconState == null) { @@ -469,11 +469,11 @@ public class NotificationIconContainer extends ViewGroup { * If this is not a whole number, the fraction means by how much the icon is appearing. */ public void calculateIconXTranslations() { - float translationX = getActualPaddingStart(); + float translationX = getLeftBound(); int firstOverflowIndex = -1; int childCount = getChildCount(); int maxVisibleIcons = mMaxIcons; - float layoutEnd = getLayoutEnd(); + float layoutRight = getRightBound(); mVisualOverflowStart = 0; mFirstVisibleIconState = null; for (int i = 0; i < childCount; i++) { @@ -495,7 +495,7 @@ public class NotificationIconContainer extends ViewGroup { final boolean forceOverflow = shouldForceOverflow(i, mSpeedBumpIndex, iconState.iconAppearAmount, maxVisibleIcons); final boolean isOverflowing = forceOverflow || isOverflowing( - /* isLastChild= */ i == childCount - 1, translationX, layoutEnd, mIconSize); + /* isLastChild= */ i == childCount - 1, translationX, layoutRight, mIconSize); // First icon to overflow. if (firstOverflowIndex == -1 && isOverflowing) { @@ -536,8 +536,7 @@ public class NotificationIconContainer extends ViewGroup { for (int i = 0; i < childCount; i++) { View view = getChildAt(i); IconState iconState = mIconStates.get(view); - iconState.setXTranslation( - getWidth() - iconState.getXTranslation() - view.getWidth()); + iconState.setXTranslation(getRtlIconTranslationX(iconState, view)); } } if (mIsolatedIcon != null) { @@ -553,6 +552,11 @@ public class NotificationIconContainer extends ViewGroup { } } + /** We need this to keep icons ordered from right to left when RTL. */ + protected float getRtlIconTranslationX(IconState iconState, View iconView) { + return getWidth() - iconState.getXTranslation() - iconView.getWidth(); + } + private float getDrawingScale(View view) { return mUseIncreasedIconScale && view instanceof StatusBarIconView ? ((StatusBarIconView) view).getIconScaleIncreased() @@ -563,11 +567,21 @@ public class NotificationIconContainer extends ViewGroup { mUseIncreasedIconScale = useIncreasedIconScale; } - private float getLayoutEnd() { + /** + * @return The right boundary (not the RTL compatible end) of the area that icons can be added. + */ + protected float getRightBound() { return getActualWidth() - getActualPaddingEnd(); } - private float getActualPaddingEnd() { + /** + * @return The left boundary (not the RTL compatible start) of the area that icons can be added. + */ + protected float getLeftBound() { + return getActualPaddingStart(); + } + + protected float getActualPaddingEnd() { if (mActualPaddingEnd == NO_VALUE) { return getPaddingEnd(); } |