Merge "Allow non-resizable to enter split screen from recent" into sc-dev

This commit is contained in:
Chris Li
2021-03-13 22:31:52 +00:00
committed by Android (Google) Code Review
9 changed files with 205 additions and 12 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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);

View File

@@ -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,

View File

@@ -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.
*

View File

@@ -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()

View File

@@ -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)
}
}
}

View File

@@ -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,

View File

@@ -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()");