Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * 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 androidx.window.extensions.embedding; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static androidx.window.extensions.embedding.DividerAttributes.RATIO_UNSET; import static androidx.window.extensions.embedding.DividerAttributes.WIDTH_UNSET; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.util.TypedValue; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; /** * Manages the rendering and interaction of the divider. */ class DividerPresenter { // TODO(b/327067596) Update based on UX guidance. @VisibleForTesting static final float DEFAULT_MIN_RATIO = 0.35f; @VisibleForTesting static final float DEFAULT_MAX_RATIO = 0.65f; @VisibleForTesting static final int DEFAULT_DIVIDER_WIDTH_DP = 24; static int getDividerWidthPx(@NonNull DividerAttributes dividerAttributes) { int dividerWidthDp = dividerAttributes.getWidthDp(); // TODO(b/329193115) support divider on secondary display final Context applicationContext = ActivityThread.currentActivityThread().getApplication(); return (int) TypedValue.applyDimension( COMPLEX_UNIT_DIP, dividerWidthDp, applicationContext.getResources().getDisplayMetrics()); } /** * Returns the container bound offset that is a result of the presence of a divider. * * The offset is the relative position change for the container edge that is next to the divider * due to the presence of the divider. The value could be negative or positive depending on the * container position. Positive values indicate that the edge is shifting towards the right * (or bottom) and negative values indicate that the edge is shifting towards the left (or top). * * @param splitAttributes the {@link SplitAttributes} of the split container that we want to * compute bounds offset. * @param position the position of the container in the split that we want to compute * bounds offset for. * @return the bounds offset in pixels. */ static int getBoundsOffsetForDivider( @NonNull SplitAttributes splitAttributes, @SplitPresenter.ContainerPosition int position) { if (!Flags.activityEmbeddingInteractiveDividerFlag()) { return 0; } final DividerAttributes dividerAttributes = splitAttributes.getDividerAttributes(); if (dividerAttributes == null) { return 0; } final int dividerWidthPx = getDividerWidthPx(dividerAttributes); return getBoundsOffsetForDivider( dividerWidthPx, splitAttributes.getSplitType(), position); } @VisibleForTesting static int getBoundsOffsetForDivider( int dividerWidthPx, @NonNull SplitAttributes.SplitType splitType, @SplitPresenter.ContainerPosition int position) { if (splitType instanceof SplitAttributes.SplitType.ExpandContainersSplitType) { // No divider is needed for the ExpandContainersSplitType. return 0; } int primaryOffset; if (splitType instanceof final SplitAttributes.SplitType.RatioSplitType splitRatio) { // When a divider is present, both containers shrink by an amount proportional to their // split ratio and sum to the width of the divider, so that the ending sizing of the // containers still maintain the same ratio. primaryOffset = (int) (dividerWidthPx * splitRatio.getRatio()); } else { // Hinge split type (and other future split types) will have the divider width equally // distributed to both containers. primaryOffset = dividerWidthPx / 2; } final int secondaryOffset = dividerWidthPx - primaryOffset; switch (position) { case CONTAINER_POSITION_LEFT: case CONTAINER_POSITION_TOP: return -primaryOffset; case CONTAINER_POSITION_RIGHT: case CONTAINER_POSITION_BOTTOM: return secondaryOffset; default: throw new IllegalArgumentException("Unknown position:" + position); } } /** * Sanitizes and sets default values in the {@link DividerAttributes}. * * Unset values will be set with system default values. See * {@link DividerAttributes#WIDTH_UNSET} and {@link DividerAttributes#RATIO_UNSET}. * * @param dividerAttributes input {@link DividerAttributes} * @return a {@link DividerAttributes} that has all values properly set. */ @Nullable static DividerAttributes sanitizeDividerAttributes( @Nullable DividerAttributes dividerAttributes) { if (dividerAttributes == null) { return null; } int widthDp = dividerAttributes.getWidthDp(); if (widthDp == WIDTH_UNSET) { widthDp = DEFAULT_DIVIDER_WIDTH_DP; } float minRatio = dividerAttributes.getPrimaryMinRatio(); if (minRatio == RATIO_UNSET) { minRatio = DEFAULT_MIN_RATIO; } float maxRatio = dividerAttributes.getPrimaryMaxRatio(); if (maxRatio == RATIO_UNSET) { maxRatio = DEFAULT_MAX_RATIO; } return new DividerAttributes.Builder(dividerAttributes) .setWidthDp(widthDp) .setPrimaryMinRatio(minRatio) .setPrimaryMaxRatio(maxRatio) .build(); } } libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +28 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package androidx.window.extensions.embedding; import static android.content.pm.PackageManager.MATCH_ALL; import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider; import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK; import android.app.Activity; Loading Loading @@ -85,10 +86,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { }) private @interface Position {} private static final int CONTAINER_POSITION_LEFT = 0; private static final int CONTAINER_POSITION_TOP = 1; private static final int CONTAINER_POSITION_RIGHT = 2; private static final int CONTAINER_POSITION_BOTTOM = 3; static final int CONTAINER_POSITION_LEFT = 0; static final int CONTAINER_POSITION_TOP = 1; static final int CONTAINER_POSITION_RIGHT = 2; static final int CONTAINER_POSITION_BOTTOM = 3; @IntDef(value = { CONTAINER_POSITION_LEFT, Loading @@ -96,7 +97,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { CONTAINER_POSITION_RIGHT, CONTAINER_POSITION_BOTTOM, }) private @interface ContainerPosition {} @interface ContainerPosition {} /** * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer, Loading Loading @@ -738,6 +739,15 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { private SplitAttributes sanitizeSplitAttributes(@NonNull TaskProperties taskProperties, @NonNull SplitAttributes splitAttributes, @Nullable Pair<Size, Size> minDimensionsPair) { // Sanitize the DividerAttributes and set default values. if (splitAttributes.getDividerAttributes() != null) { splitAttributes = new SplitAttributes.Builder(splitAttributes) .setDividerAttributes( DividerPresenter.sanitizeDividerAttributes( splitAttributes.getDividerAttributes()) ).build(); } if (minDimensionsPair == null) { return splitAttributes; } Loading Loading @@ -930,18 +940,18 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { */ private static SplitAttributes updateSplitAttributesType( @NonNull SplitAttributes splitAttributes, @NonNull SplitType splitTypeToUpdate) { return new SplitAttributes.Builder() return new SplitAttributes.Builder(splitAttributes) .setSplitType(splitTypeToUpdate) .setLayoutDirection(splitAttributes.getLayoutDirection()) .setAnimationBackground(splitAttributes.getAnimationBackground()) .build(); } @NonNull private Rect getLeftContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_LEFT); final int right = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_LEFT, foldingFeature); CONTAINER_POSITION_LEFT, foldingFeature) + dividerOffset; final Rect taskBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(taskBounds.left, taskBounds.top, right, taskBounds.bottom); } Loading @@ -949,8 +959,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getRightContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_RIGHT); final int left = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_RIGHT, foldingFeature); CONTAINER_POSITION_RIGHT, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(left, parentBounds.top, parentBounds.right, parentBounds.bottom); } Loading @@ -958,8 +970,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getTopContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_TOP); final int bottom = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_TOP, foldingFeature); CONTAINER_POSITION_TOP, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(parentBounds.left, parentBounds.top, parentBounds.right, bottom); } Loading @@ -967,8 +981,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getBottomContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_BOTTOM); final int top = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_BOTTOM, foldingFeature); CONTAINER_POSITION_BOTTOM, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(parentBounds.left, top, parentBounds.right, parentBounds.bottom); } Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * 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 androidx.window.extensions.embedding; import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP; import static org.junit.Assert.assertEquals; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; /** * Test class for {@link DividerPresenter}. * * Build/Install/Run: * atest WMJetpackUnitTests:DividerPresenterTest */ @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class DividerPresenterTest { @Test public void testSanitizeDividerAttributes_setDefaultValues() { DividerAttributes attributes = new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE).build(); DividerAttributes sanitized = DividerPresenter.sanitizeDividerAttributes(attributes); assertEquals(DividerAttributes.DIVIDER_TYPE_DRAGGABLE, sanitized.getDividerType()); assertEquals(DividerPresenter.DEFAULT_DIVIDER_WIDTH_DP, sanitized.getWidthDp()); assertEquals(DividerPresenter.DEFAULT_MIN_RATIO, sanitized.getPrimaryMinRatio(), 0.0f /* delta */); assertEquals(DividerPresenter.DEFAULT_MAX_RATIO, sanitized.getPrimaryMaxRatio(), 0.0f /* delta */); } @Test public void testSanitizeDividerAttributes_notChangingValidValues() { DividerAttributes attributes = new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE) .setWidthDp(10) .setPrimaryMinRatio(0.3f) .setPrimaryMaxRatio(0.7f) .build(); DividerAttributes sanitized = DividerPresenter.sanitizeDividerAttributes(attributes); assertEquals(attributes, sanitized); } @Test public void testGetBoundsOffsetForDivider_ratioSplitType() { final int dividerWidthPx = 100; final float splitRatio = 0.25f; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.RatioSplitType(splitRatio); final int expectedTopLeftOffset = 25; final int expectedBottomRightOffset = 75; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_ratioSplitType_withRounding() { final int dividerWidthPx = 101; final float splitRatio = 0.25f; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.RatioSplitType(splitRatio); final int expectedTopLeftOffset = 25; final int expectedBottomRightOffset = 76; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_hingeSplitType() { final int dividerWidthPx = 100; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.HingeSplitType( new SplitAttributes.SplitType.RatioSplitType(0.5f)); final int expectedTopLeftOffset = 50; final int expectedBottomRightOffset = 50; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_expandContainersSplitType() { final int dividerWidthPx = 100; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.ExpandContainersSplitType(); // Always return 0 for ExpandContainersSplitType as divider is not needed. final int expectedTopLeftOffset = 0; final int expectedBottomRightOffset = 0; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } private void assertDividerOffsetEquals( int dividerWidthPx, @NonNull SplitAttributes.SplitType splitType, int expectedTopLeftOffset, int expectedBottomRightOffset) { int offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_LEFT ); assertEquals(-expectedTopLeftOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_RIGHT ); assertEquals(expectedBottomRightOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_TOP ); assertEquals(-expectedTopLeftOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_BOTTOM ); assertEquals(expectedBottomRightOffset, offset); } } libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,10 @@ public class SplitControllerTest { doReturn(tf).when(splitContainer).getPrimaryContainer(); doReturn(tf).when(splitContainer).getSecondaryContainer(); doReturn(createTestTaskContainer()).when(splitContainer).getTaskContainer(); doReturn(createSplitRule(mActivity, mActivity)).when(splitContainer).getSplitRule(); final SplitRule splitRule = createSplitRule(mActivity, mActivity); doReturn(splitRule).when(splitContainer).getSplitRule(); doReturn(splitRule.getDefaultSplitAttributes()) .when(splitContainer).getDefaultSplitAttributes(); taskContainer = mSplitController.getTaskContainer(TASK_ID); taskContainer.addSplitContainer(splitContainer); // Add a mock SplitContainer on top of splitContainer Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * 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 androidx.window.extensions.embedding; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static androidx.window.extensions.embedding.DividerAttributes.RATIO_UNSET; import static androidx.window.extensions.embedding.DividerAttributes.WIDTH_UNSET; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.util.TypedValue; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; /** * Manages the rendering and interaction of the divider. */ class DividerPresenter { // TODO(b/327067596) Update based on UX guidance. @VisibleForTesting static final float DEFAULT_MIN_RATIO = 0.35f; @VisibleForTesting static final float DEFAULT_MAX_RATIO = 0.65f; @VisibleForTesting static final int DEFAULT_DIVIDER_WIDTH_DP = 24; static int getDividerWidthPx(@NonNull DividerAttributes dividerAttributes) { int dividerWidthDp = dividerAttributes.getWidthDp(); // TODO(b/329193115) support divider on secondary display final Context applicationContext = ActivityThread.currentActivityThread().getApplication(); return (int) TypedValue.applyDimension( COMPLEX_UNIT_DIP, dividerWidthDp, applicationContext.getResources().getDisplayMetrics()); } /** * Returns the container bound offset that is a result of the presence of a divider. * * The offset is the relative position change for the container edge that is next to the divider * due to the presence of the divider. The value could be negative or positive depending on the * container position. Positive values indicate that the edge is shifting towards the right * (or bottom) and negative values indicate that the edge is shifting towards the left (or top). * * @param splitAttributes the {@link SplitAttributes} of the split container that we want to * compute bounds offset. * @param position the position of the container in the split that we want to compute * bounds offset for. * @return the bounds offset in pixels. */ static int getBoundsOffsetForDivider( @NonNull SplitAttributes splitAttributes, @SplitPresenter.ContainerPosition int position) { if (!Flags.activityEmbeddingInteractiveDividerFlag()) { return 0; } final DividerAttributes dividerAttributes = splitAttributes.getDividerAttributes(); if (dividerAttributes == null) { return 0; } final int dividerWidthPx = getDividerWidthPx(dividerAttributes); return getBoundsOffsetForDivider( dividerWidthPx, splitAttributes.getSplitType(), position); } @VisibleForTesting static int getBoundsOffsetForDivider( int dividerWidthPx, @NonNull SplitAttributes.SplitType splitType, @SplitPresenter.ContainerPosition int position) { if (splitType instanceof SplitAttributes.SplitType.ExpandContainersSplitType) { // No divider is needed for the ExpandContainersSplitType. return 0; } int primaryOffset; if (splitType instanceof final SplitAttributes.SplitType.RatioSplitType splitRatio) { // When a divider is present, both containers shrink by an amount proportional to their // split ratio and sum to the width of the divider, so that the ending sizing of the // containers still maintain the same ratio. primaryOffset = (int) (dividerWidthPx * splitRatio.getRatio()); } else { // Hinge split type (and other future split types) will have the divider width equally // distributed to both containers. primaryOffset = dividerWidthPx / 2; } final int secondaryOffset = dividerWidthPx - primaryOffset; switch (position) { case CONTAINER_POSITION_LEFT: case CONTAINER_POSITION_TOP: return -primaryOffset; case CONTAINER_POSITION_RIGHT: case CONTAINER_POSITION_BOTTOM: return secondaryOffset; default: throw new IllegalArgumentException("Unknown position:" + position); } } /** * Sanitizes and sets default values in the {@link DividerAttributes}. * * Unset values will be set with system default values. See * {@link DividerAttributes#WIDTH_UNSET} and {@link DividerAttributes#RATIO_UNSET}. * * @param dividerAttributes input {@link DividerAttributes} * @return a {@link DividerAttributes} that has all values properly set. */ @Nullable static DividerAttributes sanitizeDividerAttributes( @Nullable DividerAttributes dividerAttributes) { if (dividerAttributes == null) { return null; } int widthDp = dividerAttributes.getWidthDp(); if (widthDp == WIDTH_UNSET) { widthDp = DEFAULT_DIVIDER_WIDTH_DP; } float minRatio = dividerAttributes.getPrimaryMinRatio(); if (minRatio == RATIO_UNSET) { minRatio = DEFAULT_MIN_RATIO; } float maxRatio = dividerAttributes.getPrimaryMaxRatio(); if (maxRatio == RATIO_UNSET) { maxRatio = DEFAULT_MAX_RATIO; } return new DividerAttributes.Builder(dividerAttributes) .setWidthDp(widthDp) .setPrimaryMinRatio(minRatio) .setPrimaryMaxRatio(maxRatio) .build(); } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +28 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package androidx.window.extensions.embedding; import static android.content.pm.PackageManager.MATCH_ALL; import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider; import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK; import android.app.Activity; Loading Loading @@ -85,10 +86,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { }) private @interface Position {} private static final int CONTAINER_POSITION_LEFT = 0; private static final int CONTAINER_POSITION_TOP = 1; private static final int CONTAINER_POSITION_RIGHT = 2; private static final int CONTAINER_POSITION_BOTTOM = 3; static final int CONTAINER_POSITION_LEFT = 0; static final int CONTAINER_POSITION_TOP = 1; static final int CONTAINER_POSITION_RIGHT = 2; static final int CONTAINER_POSITION_BOTTOM = 3; @IntDef(value = { CONTAINER_POSITION_LEFT, Loading @@ -96,7 +97,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { CONTAINER_POSITION_RIGHT, CONTAINER_POSITION_BOTTOM, }) private @interface ContainerPosition {} @interface ContainerPosition {} /** * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer, Loading Loading @@ -738,6 +739,15 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { private SplitAttributes sanitizeSplitAttributes(@NonNull TaskProperties taskProperties, @NonNull SplitAttributes splitAttributes, @Nullable Pair<Size, Size> minDimensionsPair) { // Sanitize the DividerAttributes and set default values. if (splitAttributes.getDividerAttributes() != null) { splitAttributes = new SplitAttributes.Builder(splitAttributes) .setDividerAttributes( DividerPresenter.sanitizeDividerAttributes( splitAttributes.getDividerAttributes()) ).build(); } if (minDimensionsPair == null) { return splitAttributes; } Loading Loading @@ -930,18 +940,18 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { */ private static SplitAttributes updateSplitAttributesType( @NonNull SplitAttributes splitAttributes, @NonNull SplitType splitTypeToUpdate) { return new SplitAttributes.Builder() return new SplitAttributes.Builder(splitAttributes) .setSplitType(splitTypeToUpdate) .setLayoutDirection(splitAttributes.getLayoutDirection()) .setAnimationBackground(splitAttributes.getAnimationBackground()) .build(); } @NonNull private Rect getLeftContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_LEFT); final int right = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_LEFT, foldingFeature); CONTAINER_POSITION_LEFT, foldingFeature) + dividerOffset; final Rect taskBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(taskBounds.left, taskBounds.top, right, taskBounds.bottom); } Loading @@ -949,8 +959,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getRightContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_RIGHT); final int left = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_RIGHT, foldingFeature); CONTAINER_POSITION_RIGHT, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(left, parentBounds.top, parentBounds.right, parentBounds.bottom); } Loading @@ -958,8 +970,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getTopContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_TOP); final int bottom = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_TOP, foldingFeature); CONTAINER_POSITION_TOP, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(parentBounds.left, parentBounds.top, parentBounds.right, bottom); } Loading @@ -967,8 +981,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull private Rect getBottomContainerBounds(@NonNull Configuration taskConfiguration, @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { final int dividerOffset = getBoundsOffsetForDivider( splitAttributes, CONTAINER_POSITION_BOTTOM); final int top = computeBoundaryBetweenContainers(taskConfiguration, splitAttributes, CONTAINER_POSITION_BOTTOM, foldingFeature); CONTAINER_POSITION_BOTTOM, foldingFeature) + dividerOffset; final Rect parentBounds = taskConfiguration.windowConfiguration.getBounds(); return new Rect(parentBounds.left, top, parentBounds.right, parentBounds.bottom); } Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java 0 → 100644 +159 −0 Original line number Diff line number Diff line /* * 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 androidx.window.extensions.embedding; import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP; import static org.junit.Assert.assertEquals; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; /** * Test class for {@link DividerPresenter}. * * Build/Install/Run: * atest WMJetpackUnitTests:DividerPresenterTest */ @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class DividerPresenterTest { @Test public void testSanitizeDividerAttributes_setDefaultValues() { DividerAttributes attributes = new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE).build(); DividerAttributes sanitized = DividerPresenter.sanitizeDividerAttributes(attributes); assertEquals(DividerAttributes.DIVIDER_TYPE_DRAGGABLE, sanitized.getDividerType()); assertEquals(DividerPresenter.DEFAULT_DIVIDER_WIDTH_DP, sanitized.getWidthDp()); assertEquals(DividerPresenter.DEFAULT_MIN_RATIO, sanitized.getPrimaryMinRatio(), 0.0f /* delta */); assertEquals(DividerPresenter.DEFAULT_MAX_RATIO, sanitized.getPrimaryMaxRatio(), 0.0f /* delta */); } @Test public void testSanitizeDividerAttributes_notChangingValidValues() { DividerAttributes attributes = new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE) .setWidthDp(10) .setPrimaryMinRatio(0.3f) .setPrimaryMaxRatio(0.7f) .build(); DividerAttributes sanitized = DividerPresenter.sanitizeDividerAttributes(attributes); assertEquals(attributes, sanitized); } @Test public void testGetBoundsOffsetForDivider_ratioSplitType() { final int dividerWidthPx = 100; final float splitRatio = 0.25f; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.RatioSplitType(splitRatio); final int expectedTopLeftOffset = 25; final int expectedBottomRightOffset = 75; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_ratioSplitType_withRounding() { final int dividerWidthPx = 101; final float splitRatio = 0.25f; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.RatioSplitType(splitRatio); final int expectedTopLeftOffset = 25; final int expectedBottomRightOffset = 76; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_hingeSplitType() { final int dividerWidthPx = 100; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.HingeSplitType( new SplitAttributes.SplitType.RatioSplitType(0.5f)); final int expectedTopLeftOffset = 50; final int expectedBottomRightOffset = 50; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } @Test public void testGetBoundsOffsetForDivider_expandContainersSplitType() { final int dividerWidthPx = 100; final SplitAttributes.SplitType splitType = new SplitAttributes.SplitType.ExpandContainersSplitType(); // Always return 0 for ExpandContainersSplitType as divider is not needed. final int expectedTopLeftOffset = 0; final int expectedBottomRightOffset = 0; assertDividerOffsetEquals( dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset); } private void assertDividerOffsetEquals( int dividerWidthPx, @NonNull SplitAttributes.SplitType splitType, int expectedTopLeftOffset, int expectedBottomRightOffset) { int offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_LEFT ); assertEquals(-expectedTopLeftOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_RIGHT ); assertEquals(expectedBottomRightOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_TOP ); assertEquals(-expectedTopLeftOffset, offset); offset = getBoundsOffsetForDivider( dividerWidthPx, splitType, CONTAINER_POSITION_BOTTOM ); assertEquals(expectedBottomRightOffset, offset); } }
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,10 @@ public class SplitControllerTest { doReturn(tf).when(splitContainer).getPrimaryContainer(); doReturn(tf).when(splitContainer).getSecondaryContainer(); doReturn(createTestTaskContainer()).when(splitContainer).getTaskContainer(); doReturn(createSplitRule(mActivity, mActivity)).when(splitContainer).getSplitRule(); final SplitRule splitRule = createSplitRule(mActivity, mActivity); doReturn(splitRule).when(splitContainer).getSplitRule(); doReturn(splitRule.getDefaultSplitAttributes()) .when(splitContainer).getDefaultSplitAttributes(); taskContainer = mSplitController.getTaskContainer(TASK_ID); taskContainer.addSplitContainer(splitContainer); // Add a mock SplitContainer on top of splitContainer Loading