From 379ef492ce857ed41e0425fb10ba29387aa8f8c1 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Thu, 4 May 2023 16:11:36 -0700 Subject: [PATCH 1/2] Move directional spacing logic out of ViewEntry. This changelist delegates calculating the spacing between complications to the DirectionGroup rather than the ViewEntry itself. By calculating the margin up the hierarchy, more conditions can be accounted for without passing the information down to the ViewEntries. This changelist also renames complication margin to directional spacing to better reflect how the value is used. Test: atest ComplicationLayoutParamsTest Bug: 280595239 Change-Id: I0a83ce98bcdd42d1100ebfe4ef2ab49bb2b95dc3 --- .../ComplicationLayoutEngine.java | 139 ++++++++++++------ .../ComplicationLayoutParams.java | 67 +++++---- .../dagger/ComplicationHostViewModule.java | 5 +- .../ComplicationLayoutParamsTest.java | 8 +- 4 files changed, 136 insertions(+), 83 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java index e82564dc8a898..3666889d248df 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java @@ -18,7 +18,7 @@ package com.android.systemui.complication; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION; -import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_DIRECTIONAL_SPACING_DEFAULT; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; import android.util.Log; @@ -54,6 +54,37 @@ import javax.inject.Named; public class ComplicationLayoutEngine implements Complication.VisibilityController { public static final String TAG = "ComplicationLayoutEng"; + /** + * Container for storing and operating on a tuple of margin values. + */ + public static class Margins { + public final int start; + public final int top; + public final int end; + public final int bottom; + + /** + * Default constructor with all margins set to 0. + */ + public Margins() { + this(0, 0, 0, 0); + } + + /** + * Cosntructor to specify margin in each direction. + * @param start start margin + * @param top top margin + * @param end end margin + * @param bottom bottom margin + */ + public Margins(int start, int top, int end, int bottom) { + this.start = start; + this.top = top; + this.end = end; + this.bottom = bottom; + } + } + /** * {@link ViewEntry} is an internal container, capturing information necessary for working with * a particular {@link Complication} view. @@ -65,15 +96,13 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private final Parent mParent; @Complication.Category private final int mCategory; - private final int mDefaultMargin; /** * Default constructor. {@link Parent} allows for the {@link ViewEntry}'s surrounding * view hierarchy to be accessed without traversing the entire view tree. */ ViewEntry(View view, ComplicationLayoutParams layoutParams, - TouchInsetManager.TouchInsetSession touchSession, int category, Parent parent, - int defaultMargin) { + TouchInsetManager.TouchInsetSession touchSession, int category, Parent parent) { mView = view; // Views that are generated programmatically do not have a unique id assigned to them // at construction. A new id is assigned here to enable ConstraintLayout relative @@ -84,7 +113,6 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll mTouchInsetSession = touchSession; mCategory = category; mParent = parent; - mDefaultMargin = defaultMargin; touchSession.addViewToTracking(mView); } @@ -192,23 +220,8 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll break; } - if (!isRoot) { - final int margin = mLayoutParams.getMargin(mDefaultMargin); - switch(direction) { - case ComplicationLayoutParams.DIRECTION_DOWN: - params.setMargins(0, margin, 0, 0); - break; - case ComplicationLayoutParams.DIRECTION_UP: - params.setMargins(0, 0, 0, margin); - break; - case ComplicationLayoutParams.DIRECTION_END: - params.setMarginStart(margin); - break; - case ComplicationLayoutParams.DIRECTION_START: - params.setMarginEnd(margin); - break; - } - } + final Margins margins = mParent.getMargins(this); + params.setMarginsRelative(margins.start, margins.top, margins.end, margins.bottom); }); if (mLayoutParams.constraintSpecified()) { @@ -275,7 +288,6 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private final ComplicationLayoutParams mLayoutParams; private final int mCategory; private Parent mParent; - private int mDefaultMargin; Builder(View view, TouchInsetManager.TouchInsetSession touchSession, ComplicationLayoutParams lp, @Complication.Category int category) { @@ -310,21 +322,11 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll return this; } - /** - * Sets the margin that will be applied in the direction the complication is laid out - * towards. - */ - Builder setDefaultMargin(int margin) { - mDefaultMargin = margin; - return this; - } - /** * Builds and returns the resulting {@link ViewEntry}. */ ViewEntry build() { - return new ViewEntry(mView, mLayoutParams, mTouchSession, mCategory, mParent, - mDefaultMargin); + return new ViewEntry(mView, mLayoutParams, mTouchSession, mCategory, mParent); } } @@ -336,6 +338,11 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll * Indicates the {@link ViewEntry} requests removal. */ void removeEntry(ViewEntry entry); + + /** + * Returns the margins to be applied to the entry + */ + Margins getMargins(ViewEntry entry); } } @@ -347,6 +354,12 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private static class PositionGroup implements DirectionGroup.Parent { private final HashMap mDirectionGroups = new HashMap<>(); + private final int mDefaultDirectionalSpacing; + + PositionGroup(int defaultDirectionalSpacing) { + mDefaultDirectionalSpacing = defaultDirectionalSpacing; + } + /** * Invoked by the {@link PositionGroup} holder to introduce a {@link Complication} view to * this group. It is assumed that the caller has correctly identified this @@ -356,7 +369,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll public ViewEntry add(ViewEntry.Builder entryBuilder) { final int direction = entryBuilder.getLayoutParams().getDirection(); if (!mDirectionGroups.containsKey(direction)) { - mDirectionGroups.put(direction, new DirectionGroup(this)); + mDirectionGroups.put(direction, new DirectionGroup(this, direction)); } return mDirectionGroups.get(direction).add(entryBuilder); @@ -370,6 +383,11 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll updateViews(); } + @Override + public int getDefaultDirectionalSpacing() { + return mDefaultDirectionalSpacing; + } + private void updateViews() { ViewEntry head = null; @@ -417,17 +435,22 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll * {@link DirectionGroup}. */ void onEntriesChanged(); + + /** + * Returns the default spacing between elements. + */ + int getDefaultDirectionalSpacing(); } private final ArrayList mViews = new ArrayList<>(); private final Parent mParent; + private final int mDirection; /** - * Creates a new {@link DirectionGroup} with the specified parent. Note that the - * {@link DirectionGroup} does not store its own direction. It is the responsibility of the - * {@link DirectionGroup.Parent} to maintain this association. + * Creates a new {@link DirectionGroup} with the specified parent. */ - DirectionGroup(Parent parent) { + DirectionGroup(Parent parent, int direction) { mParent = parent; + mDirection = direction; } /** @@ -463,6 +486,33 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll mParent.onEntriesChanged(); } + @Override + public Margins getMargins(ViewEntry entry) { + int directionalSpacing = entry.getLayoutParams().getDirectionalSpacing( + mParent.getDefaultDirectionalSpacing()); + + Margins margins = new Margins(); + + if (getHead() != entry) { + switch (mDirection) { + case ComplicationLayoutParams.DIRECTION_START: + margins = new Margins(0, 0, directionalSpacing, 0); + break; + case ComplicationLayoutParams.DIRECTION_UP: + margins = new Margins(0, 0, 0, directionalSpacing); + break; + case ComplicationLayoutParams.DIRECTION_END: + margins = new Margins(directionalSpacing, 0, 0, 0); + break; + case ComplicationLayoutParams.DIRECTION_DOWN: + margins = new Margins(0, directionalSpacing, 0, 0); + break; + } + } + + return margins; + } + /** * Invoked by {@link Parent} to update the layout of all children {@link ViewEntry} with * the specified head. Note that the head might not be in this group and instead part of a @@ -484,7 +534,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll } private final ConstraintLayout mLayout; - private final int mDefaultMargin; + private final int mDefaultDirectionalSpacing; private final HashMap mEntries = new HashMap<>(); private final HashMap mPositions = new HashMap<>(); private final TouchInsetManager.TouchInsetSession mSession; @@ -494,12 +544,12 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll /** */ @Inject public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout, - @Named(COMPLICATION_MARGIN_DEFAULT) int defaultMargin, + @Named(COMPLICATION_DIRECTIONAL_SPACING_DEFAULT) int defaultDirectionalSpacing, TouchInsetManager.TouchInsetSession session, @Named(COMPLICATIONS_FADE_IN_DURATION) int fadeInDuration, @Named(COMPLICATIONS_FADE_OUT_DURATION) int fadeOutDuration) { mLayout = layout; - mDefaultMargin = defaultMargin; + mDefaultDirectionalSpacing = defaultDirectionalSpacing; mSession = session; mFadeInDuration = fadeInDuration; mFadeOutDuration = fadeOutDuration; @@ -537,13 +587,12 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll removeComplication(id); } - final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, mSession, lp, category) - .setDefaultMargin(mDefaultMargin); + final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, mSession, lp, category); // Add position group if doesn't already exist final int position = lp.getPosition(); if (!mPositions.containsKey(position)) { - mPositions.put(position, new PositionGroup()); + mPositions.put(position, new PositionGroup(mDefaultDirectionalSpacing)); } // Insert entry into group diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java index 71ba720a9589d..42b4efdbadb32 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java @@ -51,7 +51,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { private static final int FIRST_POSITION = POSITION_TOP; private static final int LAST_POSITION = POSITION_END; - private static final int MARGIN_UNSPECIFIED = 0xFFFFFFFF; + private static final int DIRECTIONAL_SPACING_UNSPECIFIED = 0xFFFFFFFF; private static final int CONSTRAINT_UNSPECIFIED = 0xFFFFFFFF; @Retention(RetentionPolicy.SOURCE) @@ -80,7 +80,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { private final int mWeight; - private final int mMargin; + private final int mDirectionalSpacing; private final int mConstraint; @@ -113,7 +113,25 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { */ public ComplicationLayoutParams(int width, int height, @Position int position, @Direction int direction, int weight) { - this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, CONSTRAINT_UNSPECIFIED, + this(width, height, position, direction, weight, DIRECTIONAL_SPACING_UNSPECIFIED, + CONSTRAINT_UNSPECIFIED, false); + } + + /** + * Constructs a {@link ComplicationLayoutParams}. + * @param width The width {@link android.view.View.MeasureSpec} for the view. + * @param height The height {@link android.view.View.MeasureSpec} for the view. + * @param position The place within the parent container where the view should be positioned. + * @param direction The direction the view should be laid out from either the parent container + * or preceding view. + * @param weight The weight that should be considered for this view when compared to other + * views. This has an impact on the placement of the view but not the rendering of + * the view. + * @param directionalSpacing The spacing to apply between complications. + */ + public ComplicationLayoutParams(int width, int height, @Position int position, + @Direction int direction, int weight, int directionalSpacing) { + this(width, height, position, direction, weight, directionalSpacing, CONSTRAINT_UNSPECIFIED, false); } @@ -127,31 +145,14 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { * @param weight The weight that should be considered for this view when compared to other * views. This has an impact on the placement of the view but not the rendering of * the view. - * @param margin The margin to apply between complications. - */ - public ComplicationLayoutParams(int width, int height, @Position int position, - @Direction int direction, int weight, int margin) { - this(width, height, position, direction, weight, margin, CONSTRAINT_UNSPECIFIED, false); - } - - /** - * Constructs a {@link ComplicationLayoutParams}. - * @param width The width {@link android.view.View.MeasureSpec} for the view. - * @param height The height {@link android.view.View.MeasureSpec} for the view. - * @param position The place within the parent container where the view should be positioned. - * @param direction The direction the view should be laid out from either the parent container - * or preceding view. - * @param weight The weight that should be considered for this view when compared to other - * views. This has an impact on the placement of the view but not the rendering of - * the view. - * @param margin The margin to apply between complications. + * @param directionalSpacing The spacing to apply between complications. * @param constraint The max width or height the complication is allowed to spread, depending on * its direction. For horizontal directions, this would be applied on width, * and for vertical directions, height. */ public ComplicationLayoutParams(int width, int height, @Position int position, - @Direction int direction, int weight, int margin, int constraint) { - this(width, height, position, direction, weight, margin, constraint, false); + @Direction int direction, int weight, int directionalSpacing, int constraint) { + this(width, height, position, direction, weight, directionalSpacing, constraint, false); } /** @@ -172,8 +173,8 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { */ public ComplicationLayoutParams(int width, int height, @Position int position, @Direction int direction, int weight, boolean snapToGuide) { - this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, CONSTRAINT_UNSPECIFIED, - snapToGuide); + this(width, height, position, direction, weight, DIRECTIONAL_SPACING_UNSPECIFIED, + CONSTRAINT_UNSPECIFIED, snapToGuide); } /** @@ -186,7 +187,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { * @param weight The weight that should be considered for this view when compared to other * views. This has an impact on the placement of the view but not the rendering of * the view. - * @param margin The margin to apply between complications. + * @param directionalSpacing The spacing to apply between complications. * @param constraint The max width or height the complication is allowed to spread, depending on * its direction. For horizontal directions, this would be applied on width, * and for vertical directions, height. @@ -197,7 +198,8 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { * from the end of the parent to the guide. */ public ComplicationLayoutParams(int width, int height, @Position int position, - @Direction int direction, int weight, int margin, int constraint, boolean snapToGuide) { + @Direction int direction, int weight, int directionalSpacing, int constraint, + boolean snapToGuide) { super(width, height); if (!validatePosition(position)) { @@ -213,7 +215,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { mWeight = weight; - mMargin = margin; + mDirectionalSpacing = directionalSpacing; mConstraint = constraint; @@ -228,7 +230,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { mPosition = source.mPosition; mDirection = source.mDirection; mWeight = source.mWeight; - mMargin = source.mMargin; + mDirectionalSpacing = source.mDirectionalSpacing; mConstraint = source.mConstraint; mSnapToGuide = source.mSnapToGuide; } @@ -300,11 +302,12 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { } /** - * Returns the margin to apply between complications, or the given default if no margin is + * Returns the spacing to apply between complications, or the given default if no spacing is * specified. */ - public int getMargin(int defaultMargin) { - return mMargin == MARGIN_UNSPECIFIED ? defaultMargin : mMargin; + public int getDirectionalSpacing(int defaultSpacing) { + return mDirectionalSpacing == DIRECTIONAL_SPACING_UNSPECIFIED + ? defaultSpacing : mDirectionalSpacing; } /** diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java index 1158565b9c379..7ff69b77025e9 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java @@ -36,7 +36,8 @@ import javax.inject.Named; @Module public abstract class ComplicationHostViewModule { public static final String SCOPED_COMPLICATIONS_LAYOUT = "scoped_complications_layout"; - public static final String COMPLICATION_MARGIN_DEFAULT = "complication_margin_default"; + public static final String COMPLICATION_DIRECTIONAL_SPACING_DEFAULT = + "complication_directional_spacing_default"; public static final String COMPLICATIONS_FADE_OUT_DURATION = "complications_fade_out_duration"; public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration"; public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout"; @@ -58,7 +59,7 @@ public abstract class ComplicationHostViewModule { } @Provides - @Named(COMPLICATION_MARGIN_DEFAULT) + @Named(COMPLICATION_DIRECTIONAL_SPACING_DEFAULT) static int providesComplicationPadding(@Main Resources resources) { return resources.getDimensionPixelSize(R.dimen.dream_overlay_complication_margin); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java index 286972db57a34..a23e9e40959a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java @@ -112,7 +112,7 @@ public class ComplicationLayoutParamsTest extends SysuiTestCase { ComplicationLayoutParams.POSITION_TOP, ComplicationLayoutParams.DIRECTION_DOWN, 3); - assertThat(params.getMargin(10) == 10).isTrue(); + assertThat(params.getDirectionalSpacing(10) == 10).isTrue(); } /** @@ -127,7 +127,7 @@ public class ComplicationLayoutParamsTest extends SysuiTestCase { ComplicationLayoutParams.DIRECTION_DOWN, 3, 10); - assertThat(params.getMargin(5) == 10).isTrue(); + assertThat(params.getDirectionalSpacing(5) == 10).isTrue(); } /** @@ -148,7 +148,7 @@ public class ComplicationLayoutParamsTest extends SysuiTestCase { assertThat(copy.getDirection() == params.getDirection()).isTrue(); assertThat(copy.getPosition() == params.getPosition()).isTrue(); assertThat(copy.getWeight() == params.getWeight()).isTrue(); - assertThat(copy.getMargin(0) == params.getMargin(1)).isTrue(); + assertThat(copy.getDirectionalSpacing(0) == params.getDirectionalSpacing(1)).isTrue(); assertThat(copy.getConstraint() == params.getConstraint()).isTrue(); assertThat(copy.height == params.height).isTrue(); assertThat(copy.width == params.width).isTrue(); @@ -171,7 +171,7 @@ public class ComplicationLayoutParamsTest extends SysuiTestCase { assertThat(copy.getDirection() == params.getDirection()).isTrue(); assertThat(copy.getPosition() == params.getPosition()).isTrue(); assertThat(copy.getWeight() == params.getWeight()).isTrue(); - assertThat(copy.getMargin(1) == params.getMargin(1)).isTrue(); + assertThat(copy.getDirectionalSpacing(1) == params.getDirectionalSpacing(1)).isTrue(); assertThat(copy.height == params.height).isTrue(); assertThat(copy.width == params.width).isTrue(); } From 2f4e8e92f83e4c4af52c8a66f879fafd649a4b28 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Fri, 5 May 2023 15:28:38 -0700 Subject: [PATCH 2/2] Handle overlay edge spacing within individual complications layouts. This change accounts for spacing from the layout edge in each complication, rather than using the ViewGroup's padding setting. This change resolves clipping during transitions due to an interaction between the ViewGroup padding and alpha/translation animations. This spacing calculated in margin calculation, now spread across each logical complication container. The directional group applies margins between each complication, while the position group applies margins from the layout's edge. Test: atest ComplicationLayoutEngineTest Fixes: 280595239 Change-Id: Ibe4ba52b970337671fec0c0878e2686b5bac8fa2 --- .../res/layout/dream_overlay_container.xml | 4 - .../ComplicationLayoutEngine.java | 114 ++++++++++++++++-- .../dagger/ComplicationHostViewModule.java | 32 +++++ .../ComplicationLayoutEngineTest.java | 113 +++++++++++++---- 4 files changed, 223 insertions(+), 40 deletions(-) diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml index ae0a9374fd2c4..19fb874ea2bee 100644 --- a/packages/SystemUI/res/layout/dream_overlay_container.xml +++ b/packages/SystemUI/res/layout/dream_overlay_container.xml @@ -25,10 +25,6 @@ android:id="@+id/dream_overlay_content" android:layout_width="match_parent" android:layout_height="0dp" - android:paddingTop="@dimen/dream_overlay_container_padding_top" - android:paddingEnd="@dimen/dream_overlay_container_padding_end" - android:paddingBottom="@dimen/dream_overlay_container_padding_bottom" - android:paddingStart="@dimen/dream_overlay_container_padding_start" android:clipToPadding="false" android:clipChildren="false" app:layout_constraintTop_toBottomOf="@id/dream_overlay_status_bar" diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java index 3666889d248df..e1dd1a69158bd 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java @@ -16,9 +16,21 @@ package com.android.systemui.complication; +import static com.android.systemui.complication.ComplicationLayoutParams.DIRECTION_DOWN; +import static com.android.systemui.complication.ComplicationLayoutParams.DIRECTION_END; +import static com.android.systemui.complication.ComplicationLayoutParams.DIRECTION_START; +import static com.android.systemui.complication.ComplicationLayoutParams.DIRECTION_UP; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_END; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_START; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_DIRECTIONAL_SPACING_DEFAULT; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_POSITION_BOTTOM; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_POSITION_END; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_POSITION_START; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_POSITION_TOP; import static com.android.systemui.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; import android.util.Log; @@ -29,6 +41,7 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Constraints; import com.android.systemui.R; +import com.android.systemui.complication.ComplicationLayoutParams.Direction; import com.android.systemui.complication.ComplicationLayoutParams.Position; import com.android.systemui.complication.dagger.ComplicationModule; import com.android.systemui.statusbar.CrossFadeHelper; @@ -83,6 +96,16 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll this.end = end; this.bottom = bottom; } + + /** + * Creates a new {@link Margins} by adding the corresponding dimensions together. + */ + public static Margins combine(Margins margins1, Margins margins2) { + return new Margins(margins1.start + margins2.start, + margins1.top + margins2.top, + margins1.end + margins2.end, + margins1.bottom + margins2.bottom); + } } /** @@ -220,7 +243,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll break; } - final Margins margins = mParent.getMargins(this); + final Margins margins = mParent.getMargins(this, isRoot); params.setMarginsRelative(margins.start, margins.top, margins.end, margins.bottom); }); @@ -342,7 +365,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll /** * Returns the margins to be applied to the entry */ - Margins getMargins(ViewEntry entry); + Margins getMargins(ViewEntry entry, boolean isRoot); } } @@ -354,10 +377,13 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private static class PositionGroup implements DirectionGroup.Parent { private final HashMap mDirectionGroups = new HashMap<>(); + private final HashMap mDirectionalMargins; + private final int mDefaultDirectionalSpacing; - PositionGroup(int defaultDirectionalSpacing) { + PositionGroup(int defaultDirectionalSpacing, HashMap directionalMargins) { mDefaultDirectionalSpacing = defaultDirectionalSpacing; + mDirectionalMargins = directionalMargins; } /** @@ -369,7 +395,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll public ViewEntry add(ViewEntry.Builder entryBuilder) { final int direction = entryBuilder.getLayoutParams().getDirection(); if (!mDirectionGroups.containsKey(direction)) { - mDirectionGroups.put(direction, new DirectionGroup(this, direction)); + mDirectionGroups.put(direction, new DirectionGroup(this)); } return mDirectionGroups.get(direction).add(entryBuilder); @@ -388,6 +414,21 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll return mDefaultDirectionalSpacing; } + @Override + public Margins getMargins(ViewEntry entry, boolean isRoot) { + if (isRoot) { + Margins cumulativeMargins = new Margins(); + + for (Margins margins : mDirectionalMargins.values()) { + cumulativeMargins = Margins.combine(margins, cumulativeMargins); + } + + return cumulativeMargins; + } + + return mDirectionalMargins.get(entry.getLayoutParams().getDirection()); + } + private void updateViews() { ViewEntry head = null; @@ -440,17 +481,20 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll * Returns the default spacing between elements. */ int getDefaultDirectionalSpacing(); + + /** + * Returns the margins for the view entry. + */ + Margins getMargins(ViewEntry entry, boolean isRoot); } private final ArrayList mViews = new ArrayList<>(); private final Parent mParent; - private final int mDirection; /** * Creates a new {@link DirectionGroup} with the specified parent. */ - DirectionGroup(Parent parent, int direction) { + DirectionGroup(Parent parent) { mParent = parent; - mDirection = direction; } /** @@ -487,14 +531,14 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll } @Override - public Margins getMargins(ViewEntry entry) { + public Margins getMargins(ViewEntry entry, boolean isRoot) { int directionalSpacing = entry.getLayoutParams().getDirectionalSpacing( mParent.getDefaultDirectionalSpacing()); Margins margins = new Margins(); - if (getHead() != entry) { - switch (mDirection) { + if (!isRoot) { + switch (entry.getLayoutParams().getDirection()) { case ComplicationLayoutParams.DIRECTION_START: margins = new Margins(0, 0, directionalSpacing, 0); break; @@ -510,7 +554,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll } } - return margins; + return Margins.combine(mParent.getMargins(entry, isRoot), margins); } /** @@ -540,11 +584,16 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private final TouchInsetManager.TouchInsetSession mSession; private final int mFadeInDuration; private final int mFadeOutDuration; + private final HashMap> mPositionDirectionMarginMapping; /** */ @Inject public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout, @Named(COMPLICATION_DIRECTIONAL_SPACING_DEFAULT) int defaultDirectionalSpacing, + @Named(COMPLICATION_MARGIN_POSITION_START) int complicationMarginPositionStart, + @Named(COMPLICATION_MARGIN_POSITION_TOP) int complicationMarginPositionTop, + @Named(COMPLICATION_MARGIN_POSITION_END) int complicationMarginPositionEnd, + @Named(COMPLICATION_MARGIN_POSITION_BOTTOM) int complicationMarginPositionBottom, TouchInsetManager.TouchInsetSession session, @Named(COMPLICATIONS_FADE_IN_DURATION) int fadeInDuration, @Named(COMPLICATIONS_FADE_OUT_DURATION) int fadeOutDuration) { @@ -553,6 +602,46 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll mSession = session; mFadeInDuration = fadeInDuration; mFadeOutDuration = fadeOutDuration; + mPositionDirectionMarginMapping = generatePositionDirectionalMarginsMapping( + complicationMarginPositionStart, + complicationMarginPositionTop, + complicationMarginPositionEnd, + complicationMarginPositionBottom); + } + + private static HashMap> + generatePositionDirectionalMarginsMapping(int complicationMarginPositionStart, + int complicationMarginPositionTop, + int complicationMarginPositionEnd, + int complicationMarginPositionBottom) { + HashMap> mapping = new HashMap<>(); + + final Margins startMargins = new Margins(complicationMarginPositionStart, 0, 0, 0); + final Margins topMargins = new Margins(0, complicationMarginPositionTop, 0, 0); + final Margins endMargins = new Margins(0, 0, complicationMarginPositionEnd, 0); + final Margins bottomMargins = new Margins(0, 0, 0, complicationMarginPositionBottom); + + addToMapping(mapping, POSITION_START | POSITION_TOP, DIRECTION_END, topMargins); + addToMapping(mapping, POSITION_START | POSITION_TOP, DIRECTION_DOWN, startMargins); + + addToMapping(mapping, POSITION_START | POSITION_BOTTOM, DIRECTION_END, bottomMargins); + addToMapping(mapping, POSITION_START | POSITION_BOTTOM, DIRECTION_UP, startMargins); + + addToMapping(mapping, POSITION_END | POSITION_TOP, DIRECTION_START, topMargins); + addToMapping(mapping, POSITION_END | POSITION_TOP, DIRECTION_DOWN, endMargins); + + addToMapping(mapping, POSITION_END | POSITION_BOTTOM, DIRECTION_START, bottomMargins); + addToMapping(mapping, POSITION_END | POSITION_BOTTOM, DIRECTION_UP, endMargins); + + return mapping; + } + + private static void addToMapping(HashMap> mapping, + @Position int position, @Direction int direction, Margins margins) { + if (!mapping.containsKey(position)) { + mapping.put(position, new HashMap<>()); + } + mapping.get(position).put(direction, margins); } @Override @@ -592,7 +681,8 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll // Add position group if doesn't already exist final int position = lp.getPosition(); if (!mPositions.containsKey(position)) { - mPositions.put(position, new PositionGroup(mDefaultDirectionalSpacing)); + mPositions.put(position, new PositionGroup(mDefaultDirectionalSpacing, + mPositionDirectionMarginMapping.get(lp.getPosition()))); } // Insert entry into group diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java index 7ff69b77025e9..a7d017dda21e3 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java @@ -42,6 +42,14 @@ public abstract class ComplicationHostViewModule { public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration"; public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout"; public static final String COMPLICATIONS_FADE_OUT_DELAY = "complication_fade_out_delay"; + public static final String COMPLICATION_MARGIN_POSITION_START = + "complication_margin_position_start"; + public static final String COMPLICATION_MARGIN_POSITION_TOP = + "complication_margin_position_top"; + public static final String COMPLICATION_MARGIN_POSITION_END = + "complication_margin_position_end"; + public static final String COMPLICATION_MARGIN_POSITION_BOTTOM = + "complication_margin_position_bottom"; /** * Generates a {@link ConstraintLayout}, which can host @@ -64,6 +72,30 @@ public abstract class ComplicationHostViewModule { return resources.getDimensionPixelSize(R.dimen.dream_overlay_complication_margin); } + @Provides + @Named(COMPLICATION_MARGIN_POSITION_START) + static int providesComplicationMarginPositionStart(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_container_padding_start); + } + + @Provides + @Named(COMPLICATION_MARGIN_POSITION_TOP) + static int providesComplicationMarginPositionTop(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_container_padding_top); + } + + @Provides + @Named(COMPLICATION_MARGIN_POSITION_END) + static int providesComplicationMarginPositionEnd(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_container_padding_end); + } + + @Provides + @Named(COMPLICATION_MARGIN_POSITION_BOTTOM) + static int providesComplicationMarginPositionBottom(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_container_padding_bottom); + } + /** * Provides the fade out duration for complications. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java index a1d4fb4dd5832..69d8d0b6f0915 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java @@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.complication.ComplicationLayoutEngine.Margins; import com.android.systemui.touch.TouchInsetManager; import org.junit.Before; @@ -42,6 +43,7 @@ import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.List; +import java.util.Random; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -54,6 +56,14 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { @Mock TouchInsetManager.TouchInsetSession mTouchSession; + ComplicationLayoutEngine createComplicationLayoutEngine() { + return createComplicationLayoutEngine(0); + } + + ComplicationLayoutEngine createComplicationLayoutEngine(int spacing) { + return new ComplicationLayoutEngine(mLayout, spacing, 0, 0, 0, 0, mTouchSession, 0, 0); + } + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -104,6 +114,73 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { engine.addComplication(info.id, info.view, info.lp, info.category); } + @Test + public void testCombineMargins() { + final Random rand = new Random(); + final Margins margins1 = new Margins(rand.nextInt(), rand.nextInt(), rand.nextInt(), + rand.nextInt()); + final Margins margins2 = new Margins(rand.nextInt(), rand.nextInt(), rand.nextInt(), + rand.nextInt()); + final Margins combined = Margins.combine(margins1, margins2); + assertThat(margins1.start + margins2.start).isEqualTo(combined.start); + assertThat(margins1.top + margins2.top).isEqualTo(combined.top); + assertThat(margins1.end + margins2.end).isEqualTo(combined.end); + assertThat(margins1.bottom + margins2.bottom).isEqualTo(combined.bottom); + } + + @Test + public void testComplicationMarginPosition() { + final Random rand = new Random(); + final int startMargin = rand.nextInt(); + final int topMargin = rand.nextInt(); + final int endMargin = rand.nextInt(); + final int bottomMargin = rand.nextInt(); + final int spacing = rand.nextInt(); + + final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, spacing, + startMargin, topMargin, endMargin, bottomMargin, mTouchSession, 0, 0); + + final ViewInfo firstViewInfo = new ViewInfo( + new ComplicationLayoutParams( + 100, + 100, + ComplicationLayoutParams.POSITION_TOP + | ComplicationLayoutParams.POSITION_END, + ComplicationLayoutParams.DIRECTION_DOWN, + 0), + Complication.CATEGORY_SYSTEM, + mLayout); + + addComplication(engine, firstViewInfo); + firstViewInfo.clearInvocations(); + + final ViewInfo secondViewInfo = new ViewInfo( + new ComplicationLayoutParams( + 100, + 100, + ComplicationLayoutParams.POSITION_TOP + | ComplicationLayoutParams.POSITION_END, + ComplicationLayoutParams.DIRECTION_DOWN, + 0), + Complication.CATEGORY_STANDARD, + mLayout); + + addComplication(engine, secondViewInfo); + + + // The first added view should have margins from both directions from the corner position. + verifyChange(firstViewInfo, false, lp -> { + assertThat(lp.topMargin).isEqualTo(topMargin); + assertThat(lp.getMarginEnd()).isEqualTo(endMargin); + }); + + // The second view should be spaced below the first view and have the side end margin. + verifyChange(secondViewInfo, false, lp -> { + assertThat(lp.topMargin).isEqualTo(spacing); + assertThat(lp.getMarginEnd()).isEqualTo(endMargin); + }); + } + /** * Makes sure the engine properly places a view within the {@link ConstraintLayout}. */ @@ -120,8 +197,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { Complication.CATEGORY_STANDARD, mLayout); - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); addComplication(engine, firstViewInfo); // Ensure the view is added to the top end corner @@ -148,8 +224,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { Complication.CATEGORY_STANDARD, mLayout); - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); addComplication(engine, firstViewInfo); // Ensure the view is added to the top end corner @@ -165,8 +240,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { */ @Test public void testDirectionLayout() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -214,8 +288,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { */ @Test public void testPositionLayout() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -302,8 +375,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { @Test public void testDefaultMargin() { final int margin = 5; - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, margin, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(margin); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -379,8 +451,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { public void testComplicationMargin() { final int defaultMargin = 5; final int complicationMargin = 10; - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, defaultMargin, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(defaultMargin); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -446,8 +517,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { @Test public void testWidthConstraint() { final int maxWidth = 20; - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo viewStartDirection = new ViewInfo( new ComplicationLayoutParams( @@ -495,8 +565,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { @Test public void testHeightConstraint() { final int maxHeight = 20; - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo viewUpDirection = new ViewInfo( new ComplicationLayoutParams( @@ -543,8 +612,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { */ @Test public void testConstraintNotSetWhenNotSpecified() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo view = new ViewInfo( new ComplicationLayoutParams( @@ -572,8 +640,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { */ @Test public void testRemoval() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -619,8 +686,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { */ @Test public void testDoubleRemoval() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo firstViewInfo = new ViewInfo( new ComplicationLayoutParams( @@ -649,8 +715,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { @Test public void testGetViews() { - final ComplicationLayoutEngine engine = - new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + final ComplicationLayoutEngine engine = createComplicationLayoutEngine(); final ViewInfo topEndView = new ViewInfo( new ComplicationLayoutParams(