TaskOrganizer: Add WINDOWING_MODE_MULTI_WINDOW support
Also add small test activity. Bug: 139371701 Test: TaskOrganizerTests. TaskOrganizerMultiWindowTest. Change-Id: I0bea25a5c8eef25fba88a0d056ef464035749a59
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@@ -106,9 +107,11 @@ class TaskOrganizerController {
|
||||
* and receive taskVanished callbacks in the process.
|
||||
*/
|
||||
void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
|
||||
if (windowingMode != WINDOWING_MODE_PINNED) {
|
||||
if (windowingMode != WINDOWING_MODE_PINNED &&
|
||||
windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
|
||||
throw new UnsupportedOperationException(
|
||||
"As of now only Pinned windowing mode is supported for registerTaskOrganizer");
|
||||
"As of now only Pinned and Multiwindow windowing modes are"
|
||||
+ " supported for registerTaskOrganizer");
|
||||
|
||||
}
|
||||
clearIfNeeded(windowingMode);
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
||||
@@ -63,20 +63,24 @@ import org.junit.runner.RunWith;
|
||||
@Presubmit
|
||||
@RunWith(WindowTestRunner.class)
|
||||
public class TaskOrganizerTests extends WindowTestsBase {
|
||||
private ITaskOrganizer makeAndRegisterMockOrganizer() {
|
||||
private ITaskOrganizer registerMockOrganizer(int windowingMode) {
|
||||
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
|
||||
when(organizer.asBinder()).thenReturn(new Binder());
|
||||
|
||||
mWm.mAtmService.registerTaskOrganizer(organizer, WINDOWING_MODE_PINNED);
|
||||
mWm.mAtmService.registerTaskOrganizer(organizer, windowingMode);
|
||||
|
||||
return organizer;
|
||||
}
|
||||
|
||||
private ITaskOrganizer registerMockOrganizer() {
|
||||
return registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppearVanish() throws RemoteException {
|
||||
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
|
||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
||||
|
||||
task.setTaskOrganizer(organizer);
|
||||
verify(organizer).taskAppeared(any(), any());
|
||||
@@ -89,8 +93,8 @@ public class TaskOrganizerTests extends WindowTestsBase {
|
||||
public void testSwapOrganizer() throws RemoteException {
|
||||
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
|
||||
final ITaskOrganizer organizer2 = makeAndRegisterMockOrganizer();
|
||||
final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
|
||||
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
|
||||
|
||||
task.setTaskOrganizer(organizer);
|
||||
verify(organizer).taskAppeared(any(), any());
|
||||
@@ -99,11 +103,25 @@ public class TaskOrganizerTests extends WindowTestsBase {
|
||||
verify(organizer2).taskAppeared(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwapWindowingModes() throws RemoteException {
|
||||
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
|
||||
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
|
||||
|
||||
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
verify(organizer).taskAppeared(any(), any());
|
||||
stack.setWindowingMode(WINDOWING_MODE_PINNED);
|
||||
verify(organizer).taskVanished(any());
|
||||
verify(organizer2).taskAppeared(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearOrganizer() throws RemoteException {
|
||||
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
|
||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
||||
|
||||
stack.setTaskOrganizer(organizer);
|
||||
verify(organizer).taskAppeared(any(), any());
|
||||
@@ -116,7 +134,7 @@ public class TaskOrganizerTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
|
||||
final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
|
||||
final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
|
||||
|
||||
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
|
||||
@@ -19,5 +19,11 @@
|
||||
<service android:name=".TaskOrganizerPipTest"
|
||||
android:exported="true">
|
||||
</service>
|
||||
<activity android:name="TaskOrganizerMultiWindowTest" android:label="TaskOrganizer MW Test">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.test.taskembed;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.ITaskOrganizer;
|
||||
import android.view.IWindowContainer;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class TaskOrganizerMultiWindowTest extends Activity {
|
||||
class TaskLaunchingView extends TaskView {
|
||||
TaskLaunchingView(Context c, ITaskOrganizer o, int windowingMode) {
|
||||
super(c, o, windowingMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
|
||||
startCalculatorActivity(width, height);
|
||||
}
|
||||
}
|
||||
TaskView mView;
|
||||
|
||||
class Organizer extends ITaskOrganizer.Stub {
|
||||
@Override
|
||||
public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
|
||||
mView.reparentTask(wc);
|
||||
}
|
||||
public void taskVanished(IWindowContainer wc) {
|
||||
}
|
||||
public void transactionReady(int id, SurfaceControl.Transaction t) {
|
||||
}
|
||||
}
|
||||
|
||||
Organizer mOrganizer = new Organizer();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mView = new TaskLaunchingView(this, mOrganizer, WINDOWING_MODE_MULTI_WINDOW);
|
||||
setContentView(mView);
|
||||
}
|
||||
|
||||
Intent makeCalculatorIntent() {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_APP_CALCULATOR);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
return intent;
|
||||
}
|
||||
|
||||
Bundle makeLaunchOptions(int width, int height) {
|
||||
ActivityOptions o = ActivityOptions.makeBasic();
|
||||
o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
o.setLaunchBounds(new Rect(0, 0, width, height));
|
||||
return o.toBundle();
|
||||
}
|
||||
|
||||
void startCalculatorActivity(int width, int height) {
|
||||
startActivity(makeCalculatorIntent(), makeLaunchOptions(width, height));
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.test.taskembed;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.Service;
|
||||
@@ -38,48 +40,11 @@ public class TaskOrganizerPipTest extends Service {
|
||||
static final int PIP_WIDTH = 640;
|
||||
static final int PIP_HEIGHT = 360;
|
||||
|
||||
class PipOrgView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
PipOrgView(Context c) {
|
||||
super(c);
|
||||
getHolder().addCallback(this);
|
||||
setZOrderOnTop(true);
|
||||
}
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
try {
|
||||
ActivityTaskManager.getService().registerTaskOrganizer(mOrganizer,
|
||||
WindowConfiguration.WINDOWING_MODE_PINNED);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
}
|
||||
|
||||
void reparentTask(IWindowContainer wc) {
|
||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
SurfaceControl leash = null;
|
||||
try {
|
||||
leash = wc.getLeash();
|
||||
} catch (Exception e) {
|
||||
// System server died.. oh well
|
||||
}
|
||||
t.reparent(leash, getSurfaceControl())
|
||||
.setPosition(leash, 0, 0)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
||||
PipOrgView mPipView;
|
||||
TaskView mTaskView;
|
||||
|
||||
class Organizer extends ITaskOrganizer.Stub {
|
||||
public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
|
||||
mPipView.reparentTask(wc);
|
||||
mTaskView.reparentTask(wc);
|
||||
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
wct.scheduleFinishEnterPip(wc, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
|
||||
@@ -113,8 +78,8 @@ public class TaskOrganizerPipTest extends Service {
|
||||
FrameLayout layout = new FrameLayout(this);
|
||||
ViewGroup.LayoutParams lp =
|
||||
new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
|
||||
mPipView = new PipOrgView(this);
|
||||
layout.addView(mPipView, lp);
|
||||
mTaskView = new TaskView(this, mOrganizer, WINDOWING_MODE_PINNED);
|
||||
layout.addView(mTaskView, lp);
|
||||
|
||||
WindowManager wm = getSystemService(WindowManager.class);
|
||||
wm.addView(layout, wlp);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.test.taskembed;
|
||||
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.view.ITaskOrganizer;
|
||||
import android.view.IWindowContainer;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
/**
|
||||
* Simple SurfaceView wrapper which registers a TaskOrganizer
|
||||
* after it's Surface is ready.
|
||||
*/
|
||||
class TaskView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
final ITaskOrganizer mTaskOrganizer;
|
||||
final int mWindowingMode;
|
||||
|
||||
TaskView(Context c, ITaskOrganizer o, int windowingMode) {
|
||||
super(c);
|
||||
getHolder().addCallback(this);
|
||||
setZOrderOnTop(true);
|
||||
|
||||
mTaskOrganizer = o;
|
||||
mWindowingMode = windowingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
try {
|
||||
ActivityTaskManager.getService().registerTaskOrganizer(mTaskOrganizer,
|
||||
mWindowingMode);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
}
|
||||
|
||||
void reparentTask(IWindowContainer wc) {
|
||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
SurfaceControl leash = null;
|
||||
try {
|
||||
leash = wc.getLeash();
|
||||
} catch (Exception e) {
|
||||
// System server died.. oh well
|
||||
}
|
||||
t.reparent(leash, getSurfaceControl())
|
||||
.setPosition(leash, 0, 0)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user