Merge "Allow non-resizable to enter split screen from recent" into sc-dev
This commit is contained in:
@@ -393,6 +393,20 @@ public class ActivityTaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to allow non-resizable apps to be shown in multi-window. The app will be letterboxed
|
||||
* if the request orientation is not met, and will be shown in size-compat mode if the container
|
||||
* size has changed.
|
||||
* @hide
|
||||
*/
|
||||
public static boolean supportsNonResizableMultiWindow() {
|
||||
try {
|
||||
return ActivityTaskManager.getService().supportsNonResizableMultiWindow();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the UI mode of the given config supports error dialogs (ANR, crash, etc).
|
||||
* @hide
|
||||
|
||||
@@ -289,6 +289,13 @@ interface IActivityTaskManager {
|
||||
void setSplitScreenResizing(boolean resizing);
|
||||
boolean supportsLocalVoiceInteraction();
|
||||
|
||||
/**
|
||||
* Whether to allow non-resizable apps to be shown in multi-window. The app will be letterboxed
|
||||
* if the request orientation is not met, and will be shown in size-compat mode if the container
|
||||
* size has changed.
|
||||
*/
|
||||
boolean supportsNonResizableMultiWindow();
|
||||
|
||||
// Get device configuration
|
||||
ConfigurationInfo getDeviceConfigurationInfo();
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.graphics.Rect;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.WindowContainerToken;
|
||||
@@ -88,7 +89,8 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan
|
||||
ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s",
|
||||
task1.taskId, task2.taskId, this);
|
||||
|
||||
if (!task1.isResizeable || !task2.isResizeable) {
|
||||
if ((!task1.isResizeable || !task2.isResizeable)
|
||||
&& !ActivityTaskManager.supportsNonResizableMultiWindow()) {
|
||||
ProtoLog.e(WM_SHELL_TASK_ORG,
|
||||
"Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b",
|
||||
task1.isResizeable, task2.isResizeable);
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
@@ -91,9 +92,11 @@ public class SplitScreenTransitions implements Transitions.TransitionHandler {
|
||||
// is nothing behind it.
|
||||
((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK)
|
||||
&& triggerTask.parentTaskId == mListener.mPrimary.taskId)
|
||||
// if a non-resizable is launched, we also need to leave split-screen.
|
||||
// if a non-resizable is launched when it is not supported in multi window,
|
||||
// we also need to leave split-screen.
|
||||
|| ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
|
||||
&& !triggerTask.isResizeable);
|
||||
&& !triggerTask.isResizeable
|
||||
&& !ActivityTaskManager.supportsNonResizableMultiWindow());
|
||||
// In both cases, dismiss the primary
|
||||
if (shouldDismiss) {
|
||||
WindowManagerProxy.buildDismissSplit(out, mListener,
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* Proxy to simplify calls into window manager/activity manager
|
||||
@@ -208,11 +209,17 @@ class WindowManagerProxy {
|
||||
return false;
|
||||
}
|
||||
ActivityManager.RunningTaskInfo topHomeTask = null;
|
||||
// One-time lazy wrapper to avoid duplicated IPC in loop. Not store as class variable
|
||||
// because the value can be changed at runtime.
|
||||
final BooleanSupplier supportsNonResizableMultiWindow =
|
||||
createSupportsNonResizableMultiWindowSupplier();
|
||||
for (int i = rootTasks.size() - 1; i >= 0; --i) {
|
||||
final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
|
||||
// Only move resizeable task to split secondary. However, we have an exception
|
||||
// for non-resizable home because we will minimize to show it.
|
||||
if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME) {
|
||||
// Check whether to move resizeable task to split secondary.
|
||||
// Also, we have an exception for non-resizable home because we will minimize to show
|
||||
// it.
|
||||
if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME
|
||||
&& !supportsNonResizableMultiWindow.getAsBoolean()) {
|
||||
continue;
|
||||
}
|
||||
// Only move fullscreen tasks to split secondary.
|
||||
@@ -357,6 +364,21 @@ class WindowManagerProxy {
|
||||
outWct.setFocusable(tiles.mPrimary.token, true /* focusable */);
|
||||
}
|
||||
|
||||
/** Creates a lazy wrapper to get whether it supports non-resizable in multi window. */
|
||||
private static BooleanSupplier createSupportsNonResizableMultiWindowSupplier() {
|
||||
return new BooleanSupplier() {
|
||||
private Boolean mSupportsNonResizableMultiWindow;
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
if (mSupportsNonResizableMultiWindow == null) {
|
||||
mSupportsNonResizableMultiWindow =
|
||||
ActivityTaskManager.supportsNonResizableMultiWindow();
|
||||
}
|
||||
return mSupportsNonResizableMultiWindow;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to apply a sync transaction serially with other sync transactions.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.apppairs
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.platform.test.annotations.Presubmit
|
||||
import android.provider.Settings
|
||||
import androidx.test.filters.FlakyTest
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
|
||||
@@ -26,6 +27,8 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
|
||||
import com.android.server.wm.flicker.dsl.FlickerBuilder
|
||||
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
|
||||
import com.android.wm.shell.flicker.helpers.AppPairsHelper
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -33,11 +36,10 @@ import org.junit.runners.MethodSorters
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test AppPairs launch.
|
||||
* To run this test: `atest WMShellFlickerTests:AppPairsTest`
|
||||
*/
|
||||
/**
|
||||
* Test cold launch app from launcher.
|
||||
* Test cold launch app from launcher. When the device doesn't support non-resizable in multi window
|
||||
* {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs should not pair
|
||||
* non-resizable apps.
|
||||
*
|
||||
* To run this test: `atest WMShellFlickerTests:AppPairsTestCannotPairNonResizeableApps`
|
||||
*/
|
||||
@RequiresDevice
|
||||
@@ -47,6 +49,7 @@ import org.junit.runners.Parameterized
|
||||
class AppPairsTestCannotPairNonResizeableApps(
|
||||
testSpec: FlickerTestParameter
|
||||
) : AppPairsTransition(testSpec) {
|
||||
var prevSupportNonResizableInMultiWindow = 0
|
||||
|
||||
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
|
||||
get() = {
|
||||
@@ -60,6 +63,24 @@ class AppPairsTestCannotPairNonResizeableApps(
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
|
||||
if (prevSupportNonResizableInMultiWindow == 1) {
|
||||
// Not support non-resizable in multi window
|
||||
Settings.Global.putInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
Settings.Global.putInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
|
||||
prevSupportNonResizableInMultiWindow)
|
||||
}
|
||||
|
||||
@FlakyTest
|
||||
@Test
|
||||
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.wm.shell.flicker.apppairs
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.platform.test.annotations.Presubmit
|
||||
import android.provider.Settings
|
||||
import androidx.test.filters.FlakyTest
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
|
||||
import com.android.server.wm.flicker.FlickerTestParameter
|
||||
import com.android.server.wm.flicker.FlickerTestParameterFactory
|
||||
import com.android.server.wm.flicker.dsl.FlickerBuilder
|
||||
import com.android.wm.shell.flicker.appPairsDividerIsVisible
|
||||
import com.android.wm.shell.flicker.helpers.AppPairsHelper
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test cold launch app from launcher. When the device supports non-resizable in multi window
|
||||
* {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs can pair
|
||||
* non-resizable apps.
|
||||
*
|
||||
* To run this test: `atest WMShellFlickerTests:AppPairsTestSupportPairNonResizeableApps`
|
||||
*/
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class AppPairsTestSupportPairNonResizeableApps(
|
||||
testSpec: FlickerTestParameter
|
||||
) : AppPairsTransition(testSpec) {
|
||||
var prevSupportNonResizableInMultiWindow = 0
|
||||
|
||||
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
|
||||
get() = {
|
||||
super.transition(this, it)
|
||||
transitions {
|
||||
nonResizeableApp?.launchViaIntent(wmHelper)
|
||||
// TODO pair apps through normal UX flow
|
||||
executeShellCommand(
|
||||
composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
|
||||
SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
|
||||
if (prevSupportNonResizableInMultiWindow == 0) {
|
||||
// Support non-resizable in multi window
|
||||
Settings.Global.putInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
Settings.Global.putInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
|
||||
prevSupportNonResizableInMultiWindow)
|
||||
}
|
||||
|
||||
@FlakyTest
|
||||
@Test
|
||||
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
|
||||
|
||||
@FlakyTest
|
||||
@Test
|
||||
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
|
||||
|
||||
@Presubmit
|
||||
@Test
|
||||
fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
|
||||
|
||||
@Presubmit
|
||||
@Test
|
||||
fun bothAppWindowVisible() {
|
||||
val nonResizeableApp = nonResizeableApp
|
||||
require(nonResizeableApp != null) {
|
||||
"Non resizeable app not initialized"
|
||||
}
|
||||
testSpec.assertWmEnd {
|
||||
isVisible(nonResizeableApp.defaultWindowName)
|
||||
isVisible(primaryApp.defaultWindowName)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): List<FlickerTestParameter> {
|
||||
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
|
||||
repetitions = AppPairsHelper.TEST_REPETITIONS)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.wm.shell.flicker.apppairs
|
||||
|
||||
import android.app.Instrumentation
|
||||
import android.content.Context
|
||||
import android.platform.test.annotations.Presubmit
|
||||
import android.system.helpers.ActivityHelper
|
||||
import android.util.Log
|
||||
@@ -46,6 +47,7 @@ import java.io.IOException
|
||||
|
||||
abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
|
||||
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
|
||||
protected val context: Context = instrumentation.context
|
||||
protected val isRotated = testSpec.config.startRotation.isRotated()
|
||||
protected val activityHelper = ActivityHelper.getInstance()
|
||||
protected val appPairsHelper = AppPairsHelper(instrumentation,
|
||||
|
||||
@@ -557,7 +557,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
boolean mSupportsPictureInPicture;
|
||||
boolean mSupportsMultiDisplay;
|
||||
boolean mForceResizableActivities;
|
||||
boolean mSupportsNonResizableMultiWindow;
|
||||
volatile boolean mSupportsNonResizableMultiWindow;
|
||||
|
||||
final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
|
||||
|
||||
@@ -3431,6 +3431,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
.supportsLocalVoiceInteraction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNonResizableMultiWindow() {
|
||||
return mSupportsNonResizableMultiWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateConfiguration(Configuration values) {
|
||||
mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
|
||||
|
||||
Reference in New Issue
Block a user