Merge "Remove clip adjustment to fix bottom screen flicker issue. Add a flicker test to verify animation background is no longer visible through the transition after the fix." into udc-qpr-dev am: 3dfd9e6c02
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23660587 Change-Id: Id9ac2f2565cdcc2a7b48cc1331a61cfe82366088 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -50,7 +50,7 @@ class ActivityEmbeddingAnimationAdapter {
|
|||||||
final SurfaceControl mLeash;
|
final SurfaceControl mLeash;
|
||||||
/** Area in absolute coordinate that the animation surface shouldn't go beyond. */
|
/** Area in absolute coordinate that the animation surface shouldn't go beyond. */
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Rect mWholeAnimationBounds = new Rect();
|
final Rect mWholeAnimationBounds = new Rect();
|
||||||
/**
|
/**
|
||||||
* Area in absolute coordinate that should represent all the content to show for this window.
|
* Area in absolute coordinate that should represent all the content to show for this window.
|
||||||
* This should be the end bounds for opening window, and start bounds for closing window in case
|
* This should be the end bounds for opening window, and start bounds for closing window in case
|
||||||
@@ -229,20 +229,7 @@ class ActivityEmbeddingAnimationAdapter {
|
|||||||
mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
|
mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
|
||||||
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
|
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
|
||||||
t.setAlpha(mLeash, mTransformation.getAlpha());
|
t.setAlpha(mLeash, mTransformation.getAlpha());
|
||||||
|
t.setWindowCrop(mLeash, mWholeAnimationBounds.width(), mWholeAnimationBounds.height());
|
||||||
// The following applies an inverse scale to the clip-rect so that it crops "after" the
|
|
||||||
// scale instead of before.
|
|
||||||
mVecs[1] = mVecs[2] = 0;
|
|
||||||
mVecs[0] = mVecs[3] = 1;
|
|
||||||
mTransformation.getMatrix().mapVectors(mVecs);
|
|
||||||
mVecs[0] = 1.f / mVecs[0];
|
|
||||||
mVecs[3] = 1.f / mVecs[3];
|
|
||||||
final Rect clipRect = mTransformation.getClipRect();
|
|
||||||
mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
|
|
||||||
mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
|
|
||||||
mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
|
|
||||||
mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
|
|
||||||
t.setCrop(mLeash, mRect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import android.view.animation.AlphaAnimation;
|
|||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationSet;
|
import android.view.animation.AnimationSet;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.view.animation.ClipRectAnimation;
|
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
import android.view.animation.LinearInterpolator;
|
import android.view.animation.LinearInterpolator;
|
||||||
import android.view.animation.ScaleAnimation;
|
import android.view.animation.ScaleAnimation;
|
||||||
@@ -189,14 +188,6 @@ class ActivityEmbeddingAnimationSpec {
|
|||||||
startBounds.top - endBounds.top, 0);
|
startBounds.top - endBounds.top, 0);
|
||||||
endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
|
endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
|
||||||
endSet.addAnimation(endTranslate);
|
endSet.addAnimation(endTranslate);
|
||||||
// The end leash is resizing, we should update the window crop based on the clip rect.
|
|
||||||
final Rect startClip = new Rect(startBounds);
|
|
||||||
final Rect endClip = new Rect(endBounds);
|
|
||||||
startClip.offsetTo(0, 0);
|
|
||||||
endClip.offsetTo(0, 0);
|
|
||||||
final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
|
|
||||||
clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
|
|
||||||
endSet.addAnimation(clipAnim);
|
|
||||||
endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
|
endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
|
||||||
parentBounds.height());
|
parentBounds.height());
|
||||||
endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
|
endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
package com.android.server.wm.flicker.activityembedding
|
package com.android.server.wm.flicker.activityembedding
|
||||||
|
|
||||||
import android.tools.device.flicker.legacy.LegacyFlickerTest
|
import android.tools.device.flicker.legacy.LegacyFlickerTest
|
||||||
|
import android.platform.test.annotations.Presubmit
|
||||||
|
import android.tools.common.traces.component.ComponentNameMatcher
|
||||||
import com.android.server.wm.flicker.BaseTest
|
import com.android.server.wm.flicker.BaseTest
|
||||||
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
|
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(flicker) {
|
abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(flicker) {
|
||||||
val testApp = ActivityEmbeddingAppHelper(instrumentation)
|
val testApp = ActivityEmbeddingAppHelper(instrumentation)
|
||||||
@@ -29,4 +32,14 @@ abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(
|
|||||||
// The test should only be run on devices that support ActivityEmbedding.
|
// The test should only be run on devices that support ActivityEmbedding.
|
||||||
ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
|
ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Asserts the background animation layer is never visible during bounds change transition. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun backgroundLayerNeverVisible() {
|
||||||
|
val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
|
||||||
|
flicker.assertLayers {
|
||||||
|
isInvisible(backgroundColorLayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.server.wm.flicker.activityembedding
|
||||||
|
|
||||||
|
import android.platform.test.annotations.Presubmit
|
||||||
|
import android.tools.common.datatypes.Rect
|
||||||
|
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
|
||||||
|
import android.tools.device.flicker.legacy.FlickerBuilder
|
||||||
|
import android.tools.device.flicker.legacy.LegacyFlickerTest
|
||||||
|
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
|
||||||
|
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
|
||||||
|
import androidx.test.filters.RequiresDevice
|
||||||
|
import org.junit.FixMethodOrder
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.MethodSorters
|
||||||
|
import org.junit.runners.Parameterized
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test changing split ratio at runtime on a horizona split.
|
||||||
|
*
|
||||||
|
* Setup: Launch A|B in horizontal split with B being the secondary activity, by default A and B
|
||||||
|
* windows are equal in size. B is on the top and A is on the bottom.
|
||||||
|
* Transitions:
|
||||||
|
* Change the split ratio to A:B=0.7:0.3, expect bounds change for both A and B.
|
||||||
|
*
|
||||||
|
* To run this test: `atest FlickerTests:HorizontalSplitChangeRatioTest`
|
||||||
|
*/
|
||||||
|
@RequiresDevice
|
||||||
|
@RunWith(Parameterized::class)
|
||||||
|
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :
|
||||||
|
ActivityEmbeddingTestBase(flicker) {
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
override val transition: FlickerBuilder.() -> Unit = {
|
||||||
|
setup {
|
||||||
|
tapl.setExpectedRotationCheckEnabled(false)
|
||||||
|
testApp.launchViaIntent(wmHelper)
|
||||||
|
testApp.launchSecondaryActivityHorizontally(wmHelper)
|
||||||
|
startDisplayBounds =
|
||||||
|
wmHelper.currentState.layerState.physicalDisplayBounds
|
||||||
|
?: error("Display not found")
|
||||||
|
}
|
||||||
|
transitions {
|
||||||
|
testApp.changeSecondaryActivityRatio(wmHelper)
|
||||||
|
}
|
||||||
|
teardown {
|
||||||
|
tapl.goHome()
|
||||||
|
testApp.exit(wmHelper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assert the Main activity window is always visible. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun mainActivityWindowIsAlwaysVisible() {
|
||||||
|
flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assert the Main activity window is always visible. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun mainActivityLayerIsAlwaysVisible() {
|
||||||
|
flicker.assertLayers { isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assert the Secondary activity window is always visible. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun secondaryActivityWindowIsAlwaysVisible() {
|
||||||
|
flicker.assertWm {
|
||||||
|
isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assert the Secondary activity window is always visible. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun secondaryActivityLayerIsAlwaysVisible() {
|
||||||
|
flicker.assertLayers { isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assert the Main and Secondary activity change height during the transition. */
|
||||||
|
@Presubmit
|
||||||
|
@Test
|
||||||
|
fun secondaryActivityAdjustsHeightRuntime() {
|
||||||
|
flicker.assertLayersStart {
|
||||||
|
val topLayerRegion =
|
||||||
|
this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
|
||||||
|
val bottomLayerRegion =
|
||||||
|
this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
|
||||||
|
// Compare dimensions of two splits, given we're using default split attributes,
|
||||||
|
// both activities take up the same visible size on the display.
|
||||||
|
check { "height" }
|
||||||
|
.that(topLayerRegion.region.height).isEqual(bottomLayerRegion.region.height)
|
||||||
|
check { "width" }
|
||||||
|
.that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
|
||||||
|
topLayerRegion.notOverlaps(bottomLayerRegion.region)
|
||||||
|
// Layers of two activities sum to be fullscreen size on display.
|
||||||
|
topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
flicker.assertLayersEnd {
|
||||||
|
val topLayerRegion =
|
||||||
|
this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
|
||||||
|
val bottomLayerRegion =
|
||||||
|
this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
|
||||||
|
// Compare dimensions of two splits, given we're using default split attributes,
|
||||||
|
// both activities take up the same visible size on the display.
|
||||||
|
check { "height" }
|
||||||
|
.that(topLayerRegion.region.height).isLower(bottomLayerRegion.region.height)
|
||||||
|
check { "height" }
|
||||||
|
.that(
|
||||||
|
topLayerRegion.region.height / 0.3f -
|
||||||
|
bottomLayerRegion.region.height / 0.7f)
|
||||||
|
.isLower(0.1f)
|
||||||
|
check { "width" }
|
||||||
|
.that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
|
||||||
|
topLayerRegion.notOverlaps(bottomLayerRegion.region)
|
||||||
|
// Layers of two activities sum to be fullscreen size on display.
|
||||||
|
topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
private var startDisplayBounds = Rect.EMPTY
|
||||||
|
/**
|
||||||
|
* Creates the test configurations.
|
||||||
|
*
|
||||||
|
* See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
|
||||||
|
* navigation modes.
|
||||||
|
*/
|
||||||
|
@Parameterized.Parameters(name = "{0}")
|
||||||
|
@JvmStatic
|
||||||
|
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -142,14 +142,6 @@ class OpenThirdActivityOverSplitTest(flicker: LegacyFlickerTest) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Assert the background animation layer is never visible during transition. */
|
|
||||||
@Presubmit
|
|
||||||
@Test
|
|
||||||
fun backgroundLayerNeverVisible() {
|
|
||||||
val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
|
|
||||||
flicker.assertLayers { isInvisible(backgroundColorLayer) }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
private var startDisplayBounds = Rect.EMPTY
|
private var startDisplayBounds = Rect.EMPTY
|
||||||
|
|||||||
@@ -45,18 +45,22 @@ constructor(
|
|||||||
* based on the split pair rule.
|
* based on the split pair rule.
|
||||||
*/
|
*/
|
||||||
fun launchSecondaryActivity(wmHelper: WindowManagerStateHelper) {
|
fun launchSecondaryActivity(wmHelper: WindowManagerStateHelper) {
|
||||||
val launchButton =
|
launchSecondaryActivityFromButton(wmHelper, "launch_secondary_activity_button")
|
||||||
uiDevice.wait(
|
}
|
||||||
Until.findObject(By.res(getPackage(), "launch_secondary_activity_button")),
|
|
||||||
FIND_TIMEOUT
|
/**
|
||||||
)
|
* Clicks the button to launch the secondary activity in RTL, which should split with the main
|
||||||
require(launchButton != null) { "Can't find launch secondary activity button on screen." }
|
* activity based on the split pair rule.
|
||||||
launchButton.click()
|
*/
|
||||||
wmHelper
|
fun launchSecondaryActivityRTL(wmHelper: WindowManagerStateHelper) {
|
||||||
.StateSyncBuilder()
|
launchSecondaryActivityFromButton(wmHelper, "launch_secondary_activity_rtl_button")
|
||||||
.withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
}
|
||||||
.withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
|
||||||
.waitForAndVerify()
|
/**
|
||||||
|
* Clicks the button to launch the secondary activity in a horizontal split.
|
||||||
|
*/
|
||||||
|
fun launchSecondaryActivityHorizontally(wmHelper: WindowManagerStateHelper) {
|
||||||
|
launchSecondaryActivityFromButton(wmHelper, "launch_secondary_activity_horizontally_button")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clicks the button to launch a third activity over a secondary activity. */
|
/** Clicks the button to launch a third activity over a secondary activity. */
|
||||||
@@ -101,16 +105,38 @@ constructor(
|
|||||||
*/
|
*/
|
||||||
fun finishSecondaryActivity(wmHelper: WindowManagerStateHelper) {
|
fun finishSecondaryActivity(wmHelper: WindowManagerStateHelper) {
|
||||||
val finishButton =
|
val finishButton =
|
||||||
uiDevice.wait(
|
uiDevice.wait(
|
||||||
Until.findObject(By.res(getPackage(), "finish_secondary_activity_button")),
|
Until.findObject(By.res(getPackage(), "finish_secondary_activity_button")),
|
||||||
FIND_TIMEOUT
|
FIND_TIMEOUT
|
||||||
)
|
)
|
||||||
require(finishButton != null) { "Can't find finish secondary activity button on screen." }
|
require(finishButton != null) { "Can't find finish secondary activity button on screen." }
|
||||||
finishButton.click()
|
finishButton.click()
|
||||||
wmHelper
|
wmHelper
|
||||||
.StateSyncBuilder()
|
.StateSyncBuilder()
|
||||||
.withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
|
.withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
|
||||||
.waitForAndVerify()
|
.waitForAndVerify()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clicks the button to toggle the split ratio of secondary activity.
|
||||||
|
*/
|
||||||
|
fun changeSecondaryActivityRatio(wmHelper: WindowManagerStateHelper) {
|
||||||
|
val launchButton =
|
||||||
|
uiDevice.wait(
|
||||||
|
Until.findObject(
|
||||||
|
By.res(getPackage(),
|
||||||
|
"toggle_split_ratio_button")),
|
||||||
|
FIND_TIMEOUT
|
||||||
|
)
|
||||||
|
require(launchButton != null) {
|
||||||
|
"Can't find toggle ratio for secondary activity button on screen."
|
||||||
|
}
|
||||||
|
launchButton.click()
|
||||||
|
wmHelper
|
||||||
|
.StateSyncBuilder()
|
||||||
|
.withAppTransitionIdle()
|
||||||
|
.withTransitionSnapshotGone()
|
||||||
|
.waitForAndVerify()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun secondaryActivityEnterPip(wmHelper: WindowManagerStateHelper) {
|
fun secondaryActivityEnterPip(wmHelper: WindowManagerStateHelper) {
|
||||||
@@ -149,25 +175,19 @@ constructor(
|
|||||||
.waitForAndVerify()
|
.waitForAndVerify()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun launchSecondaryActivityFromButton(
|
||||||
* Clicks the button to launch the secondary activity in RTL, which should split with the main
|
wmHelper: WindowManagerStateHelper, buttonName: String) {
|
||||||
* activity based on the split pair rule.
|
|
||||||
*/
|
|
||||||
fun launchSecondaryActivityRTL(wmHelper: WindowManagerStateHelper) {
|
|
||||||
val launchButton =
|
val launchButton =
|
||||||
uiDevice.wait(
|
uiDevice.wait(Until.findObject(By.res(getPackage(), buttonName)), FIND_TIMEOUT)
|
||||||
Until.findObject(By.res(getPackage(), "launch_secondary_activity_rtl_button")),
|
|
||||||
FIND_TIMEOUT
|
|
||||||
)
|
|
||||||
require(launchButton != null) {
|
require(launchButton != null) {
|
||||||
"Can't find launch secondary activity rtl button on screen."
|
"Can't find launch secondary activity button : " + buttonName + "on screen."
|
||||||
}
|
}
|
||||||
launchButton.click()
|
launchButton.click()
|
||||||
wmHelper
|
wmHelper
|
||||||
.StateSyncBuilder()
|
.StateSyncBuilder()
|
||||||
.withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
.withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
||||||
.withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
.withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
|
||||||
.waitForAndVerify()
|
.waitForAndVerify()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,6 +37,14 @@
|
|||||||
android:tag="RIGHT_TO_LEFT"
|
android:tag="RIGHT_TO_LEFT"
|
||||||
android:text="Launch Secondary Activity in RTL" />
|
android:text="Launch Secondary Activity in RTL" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/launch_secondary_activity_horizontally_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:onClick="launchSecondaryActivity"
|
||||||
|
android:tag="BOTTOM_TO_TOP"
|
||||||
|
android:text="Launch Secondary Activity Horizontally" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/launch_placeholder_split_button"
|
android:id="@+id/launch_placeholder_split_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -35,6 +35,14 @@
|
|||||||
android:onClick="launchThirdActivity"
|
android:onClick="launchThirdActivity"
|
||||||
android:text="Launch a third activity" />
|
android:text="Launch a third activity" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/toggle_split_ratio_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:textOn="Ratio 0.5"
|
||||||
|
android:textOff="Ratio 0.3"
|
||||||
|
android:checked="false" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/secondary_enter_pip_button"
|
android:id="@+id/secondary_enter_pip_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.window.embedding.ActivityFilter;
|
import androidx.window.embedding.ActivityFilter;
|
||||||
import androidx.window.embedding.ActivityRule;
|
import androidx.window.embedding.ActivityRule;
|
||||||
import androidx.window.embedding.EmbeddingAspectRatio;
|
import androidx.window.embedding.EmbeddingAspectRatio;
|
||||||
@@ -152,6 +153,9 @@ public class ActivityEmbeddingMainActivity extends Activity {
|
|||||||
if (layoutDirectionStr.equals(LayoutDirection.LEFT_TO_RIGHT.toString())) {
|
if (layoutDirectionStr.equals(LayoutDirection.LEFT_TO_RIGHT.toString())) {
|
||||||
return LayoutDirection.LEFT_TO_RIGHT;
|
return LayoutDirection.LEFT_TO_RIGHT;
|
||||||
}
|
}
|
||||||
|
if (layoutDirectionStr.equals(LayoutDirection.BOTTOM_TO_TOP.toString())) {
|
||||||
|
return LayoutDirection.BOTTOM_TO_TOP;
|
||||||
|
}
|
||||||
if (layoutDirectionStr.equals(LayoutDirection.RIGHT_TO_LEFT.toString())) {
|
if (layoutDirectionStr.equals(LayoutDirection.RIGHT_TO_LEFT.toString())) {
|
||||||
return LayoutDirection.RIGHT_TO_LEFT;
|
return LayoutDirection.RIGHT_TO_LEFT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ import android.app.PictureInPictureParams;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import androidx.window.embedding.SplitAttributes;
|
||||||
|
import androidx.window.embedding.SplitAttributesCalculatorParams;
|
||||||
|
import androidx.window.embedding.SplitController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity to be used as the secondary activity to split with
|
* Activity to be used as the secondary activity to split with
|
||||||
@@ -29,18 +34,41 @@ import android.view.View;
|
|||||||
*/
|
*/
|
||||||
public class ActivityEmbeddingSecondaryActivity extends Activity {
|
public class ActivityEmbeddingSecondaryActivity extends Activity {
|
||||||
|
|
||||||
|
private SplitController mSplitController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_embedding_secondary_activity_layout);
|
setContentView(R.layout.activity_embedding_secondary_activity_layout);
|
||||||
findViewById(R.id.secondary_activity_layout).setBackgroundColor(Color.YELLOW);
|
findViewById(R.id.secondary_activity_layout).setBackgroundColor(Color.YELLOW);
|
||||||
findViewById(R.id.finish_secondary_activity_button).setOnClickListener(
|
findViewById(R.id.finish_secondary_activity_button).setOnClickListener(
|
||||||
new View.OnClickListener() {
|
new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mSplitController = SplitController.getInstance(this);
|
||||||
|
final ToggleButton splitRatio = findViewById(R.id.toggle_split_ratio_button);
|
||||||
|
mSplitController.setSplitAttributesCalculator(params -> {
|
||||||
|
return new SplitAttributes.Builder()
|
||||||
|
.setSplitType(
|
||||||
|
SplitAttributes.SplitType.ratio(
|
||||||
|
splitRatio.isChecked() ? 0.7f : 0.5f)
|
||||||
|
)
|
||||||
|
.setLayoutDirection(
|
||||||
|
params.getDefaultSplitAttributes()
|
||||||
|
.getLayoutDirection())
|
||||||
|
.build();
|
||||||
|
});
|
||||||
|
splitRatio.setOnClickListener(
|
||||||
|
new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
// This triggers a recalcuation of splitatributes.
|
||||||
|
mSplitController.invalidateTopVisibleSplitAttributes();
|
||||||
|
}
|
||||||
|
});
|
||||||
findViewById(R.id.secondary_enter_pip_button).setOnClickListener(
|
findViewById(R.id.secondary_enter_pip_button).setOnClickListener(
|
||||||
new View.OnClickListener() {
|
new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user