Add TaskViewFactory.
- This CL also changes TV.setListener to have a separate Executor. Bug: 165794075 Test: atest TaskViewTest BubblesTest NewNotifPipelineBubblesTest Change-Id: Ib0324ec06d088694556f8cef6cee726d9789ce2c
This commit is contained in:
@@ -73,6 +73,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
private final CloseGuard mGuard = new CloseGuard();
|
||||
|
||||
private final ShellTaskOrganizer mTaskOrganizer;
|
||||
private final Executor mShellExecutor;
|
||||
|
||||
private ActivityManager.RunningTaskInfo mTaskInfo;
|
||||
private WindowContainerToken mTaskToken;
|
||||
@@ -81,7 +82,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
private boolean mSurfaceCreated;
|
||||
private boolean mIsInitialized;
|
||||
private Listener mListener;
|
||||
private Executor mExecutor;
|
||||
private Executor mListenerExecutor;
|
||||
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final Rect mTmpRootRect = new Rect();
|
||||
@@ -91,7 +92,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
super(context, null, 0, 0, true /* disableBackgroundLayer */);
|
||||
|
||||
mTaskOrganizer = organizer;
|
||||
mExecutor = organizer.getExecutor();
|
||||
mShellExecutor = organizer.getExecutor();
|
||||
setUseAlpha();
|
||||
getHolder().addCallback(this);
|
||||
mGuard.open("release");
|
||||
@@ -100,12 +101,13 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
/**
|
||||
* Only one listener may be set on the view, throws an exception otherwise.
|
||||
*/
|
||||
public void setListener(Listener listener) {
|
||||
public void setListener(@NonNull Executor executor, Listener listener) {
|
||||
if (mListener != null) {
|
||||
throw new IllegalStateException(
|
||||
"Trying to set a listener when one has already been set");
|
||||
}
|
||||
mListener = listener;
|
||||
mListenerExecutor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +152,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
|
||||
private void prepareActivityOptions(ActivityOptions options) {
|
||||
final Binder launchCookie = new Binder();
|
||||
mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
|
||||
mShellExecutor.execute(() -> {
|
||||
mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
|
||||
});
|
||||
options.setLaunchCookie(launchCookie);
|
||||
options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
options.setTaskAlwaysOnTop(true);
|
||||
@@ -197,11 +201,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
|
||||
private void performRelease() {
|
||||
getHolder().removeCallback(this);
|
||||
mTaskOrganizer.removeListener(this);
|
||||
resetTaskInfo();
|
||||
mShellExecutor.execute(() -> {
|
||||
mTaskOrganizer.removeListener(this);
|
||||
resetTaskInfo();
|
||||
});
|
||||
mGuard.close();
|
||||
if (mListener != null && mIsInitialized) {
|
||||
mListener.onReleased();
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onReleased();
|
||||
});
|
||||
mIsInitialized = false;
|
||||
}
|
||||
}
|
||||
@@ -218,75 +226,71 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
mTaskOrganizer.applyTransaction(wct);
|
||||
// TODO(b/151449487): Only call callback once we enable synchronization
|
||||
if (mListener != null) {
|
||||
mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
|
||||
SurfaceControl leash) {
|
||||
if (mExecutor == null) return;
|
||||
mExecutor.execute(() -> {
|
||||
mTaskInfo = taskInfo;
|
||||
mTaskToken = taskInfo.token;
|
||||
mTaskLeash = leash;
|
||||
mTaskInfo = taskInfo;
|
||||
mTaskToken = taskInfo.token;
|
||||
mTaskLeash = leash;
|
||||
|
||||
if (mSurfaceCreated) {
|
||||
// Surface is ready, so just reparent the task to this surface control
|
||||
mTransaction.reparent(mTaskLeash, getSurfaceControl())
|
||||
.show(mTaskLeash)
|
||||
.apply();
|
||||
} else {
|
||||
// The surface has already been destroyed before the task has appeared,
|
||||
// so go ahead and hide the task entirely
|
||||
updateTaskVisibility();
|
||||
}
|
||||
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true);
|
||||
// TODO: Synchronize show with the resize
|
||||
onLocationChanged();
|
||||
setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
|
||||
if (mSurfaceCreated) {
|
||||
// Surface is ready, so just reparent the task to this surface control
|
||||
mTransaction.reparent(mTaskLeash, getSurfaceControl())
|
||||
.show(mTaskLeash)
|
||||
.apply();
|
||||
} else {
|
||||
// The surface has already been destroyed before the task has appeared,
|
||||
// so go ahead and hide the task entirely
|
||||
updateTaskVisibility();
|
||||
}
|
||||
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true);
|
||||
// TODO: Synchronize show with the resize
|
||||
onLocationChanged();
|
||||
setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
|
||||
|
||||
if (mListener != null) {
|
||||
if (mListener != null) {
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
if (mExecutor == null) return;
|
||||
mExecutor.execute(() -> {
|
||||
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
|
||||
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
|
||||
|
||||
if (mListener != null) {
|
||||
if (mListener != null) {
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onTaskRemovalStarted(taskInfo.taskId);
|
||||
}
|
||||
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
|
||||
});
|
||||
}
|
||||
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);
|
||||
|
||||
// Unparent the task when this surface is destroyed
|
||||
mTransaction.reparent(mTaskLeash, null).apply();
|
||||
resetTaskInfo();
|
||||
});
|
||||
// Unparent the task when this surface is destroyed
|
||||
mTransaction.reparent(mTaskLeash, null).apply();
|
||||
resetTaskInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
if (mExecutor == null) return;
|
||||
mExecutor.execute(() -> {
|
||||
mTaskInfo.taskDescription = taskInfo.taskDescription;
|
||||
setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
|
||||
});
|
||||
mTaskInfo.taskDescription = taskInfo.taskDescription;
|
||||
setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
if (mExecutor == null) return;
|
||||
mExecutor.execute(() -> {
|
||||
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
|
||||
if (mListener != null) {
|
||||
if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
|
||||
if (mListener != null) {
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -306,17 +310,21 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
mSurfaceCreated = true;
|
||||
if (mListener != null && !mIsInitialized) {
|
||||
mIsInitialized = true;
|
||||
mListener.onInitialized();
|
||||
mListenerExecutor.execute(() -> {
|
||||
mListener.onInitialized();
|
||||
});
|
||||
}
|
||||
if (mTaskToken == null) {
|
||||
// Nothing to update, task is not yet available
|
||||
return;
|
||||
}
|
||||
// Reparent the task when this surface is created
|
||||
mTransaction.reparent(mTaskLeash, getSurfaceControl())
|
||||
.show(mTaskLeash)
|
||||
.apply();
|
||||
updateTaskVisibility();
|
||||
mShellExecutor.execute(() -> {
|
||||
if (mTaskToken == null) {
|
||||
// Nothing to update, task is not yet available
|
||||
return;
|
||||
}
|
||||
// Reparent the task when this surface is created
|
||||
mTransaction.reparent(mTaskLeash, getSurfaceControl())
|
||||
.show(mTaskLeash)
|
||||
.apply();
|
||||
updateTaskVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,14 +338,16 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mSurfaceCreated = false;
|
||||
if (mTaskToken == null) {
|
||||
// Nothing to update, task is not yet available
|
||||
return;
|
||||
}
|
||||
mShellExecutor.execute(() -> {
|
||||
if (mTaskToken == null) {
|
||||
// Nothing to update, task is not yet available
|
||||
return;
|
||||
}
|
||||
|
||||
// Unparent the task when this surface is destroyed
|
||||
mTransaction.reparent(mTaskLeash, null).apply();
|
||||
updateTaskVisibility();
|
||||
// Unparent the task when this surface is destroyed
|
||||
mTransaction.reparent(mTaskLeash, null).apply();
|
||||
updateTaskVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.annotation.UiContext;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/** Interface to create TaskView. */
|
||||
@ExternalThread
|
||||
public interface TaskViewFactory {
|
||||
/** Creates an {@link TaskView} */
|
||||
void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.annotation.UiContext;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/** Factory controller which can create {@link TaskView} */
|
||||
public class TaskViewFactoryController {
|
||||
private final ShellTaskOrganizer mTaskOrganizer;
|
||||
private final ShellExecutor mShellExecutor;
|
||||
|
||||
public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
|
||||
ShellExecutor shellExecutor) {
|
||||
mTaskOrganizer = taskOrganizer;
|
||||
mShellExecutor = shellExecutor;
|
||||
}
|
||||
|
||||
/** Creates an {@link TaskView} */
|
||||
@ShellMainThread
|
||||
public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) {
|
||||
TaskView taskView = new TaskView(context, mTaskOrganizer);
|
||||
executor.execute(() -> {
|
||||
onCreate.accept(taskView);
|
||||
});
|
||||
}
|
||||
|
||||
public TaskViewFactory getTaskViewFactory() {
|
||||
return new TaskViewFactoryImpl();
|
||||
}
|
||||
|
||||
private class TaskViewFactoryImpl implements TaskViewFactory {
|
||||
@ExternalThread
|
||||
public void create(@UiContext Context context,
|
||||
Executor executor, Consumer<TaskView> onCreate) {
|
||||
mShellExecutor.execute(() -> {
|
||||
TaskViewFactoryController.this.create(context, executor, onCreate);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +314,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
|
||||
mExpandedViewContainer.addView(mTaskView);
|
||||
bringChildToFront(mTaskView);
|
||||
mTaskView.setListener(mTaskViewListener);
|
||||
mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener);
|
||||
mPositioner = mController.getPositioner();
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ public class TaskViewTest extends ShellTestCase {
|
||||
|
||||
when(mOrganizer.getExecutor()).thenReturn(mExecutor);
|
||||
mTaskView = new TaskView(mContext, mOrganizer);
|
||||
mTaskView.setListener(mViewListener);
|
||||
mTaskView.setListener(mExecutor, mViewListener);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -112,9 +112,9 @@ public class TaskViewTest extends ShellTestCase {
|
||||
@Test
|
||||
public void testSetPendingListener_throwsException() {
|
||||
TaskView taskView = new TaskView(mContext, mOrganizer);
|
||||
taskView.setListener(mViewListener);
|
||||
taskView.setListener(mExecutor, mViewListener);
|
||||
try {
|
||||
taskView.setListener(mViewListener);
|
||||
taskView.setListener(mExecutor, mViewListener);
|
||||
} catch (IllegalStateException e) {
|
||||
// pass
|
||||
return;
|
||||
|
||||
@@ -89,6 +89,8 @@ import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.bubbles.Bubble;
|
||||
@@ -204,6 +206,8 @@ public class BubblesTest extends SysuiTestCase {
|
||||
private WindowManagerShellWrapper mWindowManagerShellWrapper;
|
||||
@Mock
|
||||
private BubbleLogger mBubbleLogger;
|
||||
@Mock
|
||||
private ShellTaskOrganizer mShellTaskOrganizer;
|
||||
|
||||
private TestableBubblePositioner mPositioner;
|
||||
|
||||
@@ -269,6 +273,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
);
|
||||
|
||||
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
|
||||
when(mShellTaskOrganizer.getExecutor()).thenReturn(new FakeExecutor(new FakeSystemClock()));
|
||||
mBubbleController = new TestableBubbleController(
|
||||
mContext,
|
||||
mBubbleData,
|
||||
@@ -279,7 +284,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mWindowManagerShellWrapper,
|
||||
mLauncherApps,
|
||||
mBubbleLogger,
|
||||
mock(ShellTaskOrganizer.class),
|
||||
mShellTaskOrganizer,
|
||||
mPositioner,
|
||||
mock(ShellExecutor.class));
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
@@ -83,6 +83,8 @@ import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.bubbles.BubbleData;
|
||||
@@ -186,6 +188,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
private WindowManagerShellWrapper mWindowManagerShellWrapper;
|
||||
@Mock
|
||||
private BubbleLogger mBubbleLogger;
|
||||
@Mock
|
||||
private ShellTaskOrganizer mShellTaskOrganizer;
|
||||
|
||||
private TestableBubblePositioner mPositioner;
|
||||
|
||||
@@ -237,6 +241,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mock(Handler.class)
|
||||
);
|
||||
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
|
||||
when(mShellTaskOrganizer.getExecutor()).thenReturn(new FakeExecutor(new FakeSystemClock()));
|
||||
mBubbleController = new TestableBubbleController(
|
||||
mContext,
|
||||
mBubbleData,
|
||||
@@ -247,7 +252,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mWindowManagerShellWrapper,
|
||||
mLauncherApps,
|
||||
mBubbleLogger,
|
||||
mock(ShellTaskOrganizer.class),
|
||||
mShellTaskOrganizer,
|
||||
mPositioner,
|
||||
mock(ShellExecutor.class));
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
Reference in New Issue
Block a user