Merge "Rename WindowDecorModelView to reflect purposes" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9fcbcb0762
@@ -82,7 +82,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
mTasks.put(taskInfo.taskId, state);
|
mTasks.put(taskInfo.taskId, state);
|
||||||
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
|
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||||
mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
|
mWindowDecorationViewModel.onTaskOpening(taskInfo, leash, t, t);
|
||||||
t.apply();
|
t.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
|
|||||||
TransitionInfo.Change change,
|
TransitionInfo.Change change,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
mWindowDecorViewModel.createWindowDecoration(
|
mWindowDecorViewModel.onTaskOpening(
|
||||||
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,32 +128,24 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
|
|||||||
TransitionInfo.Change change,
|
TransitionInfo.Change change,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
mWindowDecorViewModel.setupWindowDecorationForTransition(
|
mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT);
|
||||||
change.getTaskInfo(), startT, finishT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onChangeTransitionReady(
|
private void onChangeTransitionReady(
|
||||||
TransitionInfo.Change change,
|
TransitionInfo.Change change,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
mWindowDecorViewModel.setupWindowDecorationForTransition(
|
mWindowDecorViewModel.onTaskChanging(
|
||||||
change.getTaskInfo(), startT, finishT);
|
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onToFrontTransitionReady(
|
private void onToFrontTransitionReady(
|
||||||
TransitionInfo.Change change,
|
TransitionInfo.Change change,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
boolean exists = mWindowDecorViewModel.setupWindowDecorationForTransition(
|
mWindowDecorViewModel.onTaskChanging(
|
||||||
change.getTaskInfo(),
|
|
||||||
startT,
|
|
||||||
finishT);
|
|
||||||
if (!exists) {
|
|
||||||
// Window caption does not exist, create it
|
|
||||||
mWindowDecorViewModel.createWindowDecoration(
|
|
||||||
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTransitionStarting(@NonNull IBinder transition) {}
|
public void onTransitionStarting(@NonNull IBinder transition) {}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
|||||||
if (mWindowDecorViewModelOptional.isPresent()) {
|
if (mWindowDecorViewModelOptional.isPresent()) {
|
||||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||||
createdWindowDecor = mWindowDecorViewModelOptional.get()
|
createdWindowDecor = mWindowDecorViewModelOptional.get()
|
||||||
.createWindowDecoration(taskInfo, leash, t, t);
|
.onTaskOpening(taskInfo, leash, t, t);
|
||||||
t.apply();
|
t.apply();
|
||||||
}
|
}
|
||||||
if (!createdWindowDecor) {
|
if (!createdWindowDecor) {
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
|||||||
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model for the window decoration with a caption and shadows. Works with
|
* View model for the window decoration with a caption and shadows. Works with
|
||||||
* {@link CaptionWindowDecoration}.
|
* {@link CaptionWindowDecoration}.
|
||||||
@@ -62,6 +64,8 @@ import com.android.wm.shell.transition.Transitions;
|
|||||||
|
|
||||||
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
||||||
private static final String TAG = "CaptionViewModel";
|
private static final String TAG = "CaptionViewModel";
|
||||||
|
private final CaptionWindowDecoration.Factory mCaptionWindowDecorFactory;
|
||||||
|
private final Supplier<InputManager> mInputManagerSupplier;
|
||||||
private final ActivityTaskManager mActivityTaskManager;
|
private final ActivityTaskManager mActivityTaskManager;
|
||||||
private final ShellTaskOrganizer mTaskOrganizer;
|
private final ShellTaskOrganizer mTaskOrganizer;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
@@ -77,6 +81,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
|
|
||||||
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
|
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
|
||||||
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
|
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
|
||||||
|
private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory();
|
||||||
|
|
||||||
public CaptionWindowDecorViewModel(
|
public CaptionWindowDecorViewModel(
|
||||||
Context context,
|
Context context,
|
||||||
@@ -86,6 +91,29 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
DisplayController displayController,
|
DisplayController displayController,
|
||||||
SyncTransactionQueue syncQueue,
|
SyncTransactionQueue syncQueue,
|
||||||
DesktopModeController desktopModeController) {
|
DesktopModeController desktopModeController) {
|
||||||
|
this(
|
||||||
|
context,
|
||||||
|
mainHandler,
|
||||||
|
mainChoreographer,
|
||||||
|
taskOrganizer,
|
||||||
|
displayController,
|
||||||
|
syncQueue,
|
||||||
|
desktopModeController,
|
||||||
|
new CaptionWindowDecoration.Factory(),
|
||||||
|
InputManager::getInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CaptionWindowDecorViewModel(
|
||||||
|
Context context,
|
||||||
|
Handler mainHandler,
|
||||||
|
Choreographer mainChoreographer,
|
||||||
|
ShellTaskOrganizer taskOrganizer,
|
||||||
|
DisplayController displayController,
|
||||||
|
SyncTransactionQueue syncQueue,
|
||||||
|
DesktopModeController desktopModeController,
|
||||||
|
CaptionWindowDecoration.Factory captionWindowDecorFactory,
|
||||||
|
Supplier<InputManager> inputManagerSupplier) {
|
||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mMainHandler = mainHandler;
|
mMainHandler = mainHandler;
|
||||||
mMainChoreographer = mainChoreographer;
|
mMainChoreographer = mainChoreographer;
|
||||||
@@ -94,7 +122,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
mDisplayController = displayController;
|
mDisplayController = displayController;
|
||||||
mSyncQueue = syncQueue;
|
mSyncQueue = syncQueue;
|
||||||
mDesktopModeController = desktopModeController;
|
mDesktopModeController = desktopModeController;
|
||||||
mTransitionDragActive = false;
|
|
||||||
|
mCaptionWindowDecorFactory = captionWindowDecorFactory;
|
||||||
|
mInputManagerSupplier = inputManagerSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEventReceiverFactory(EventReceiverFactory eventReceiverFactory) {
|
||||||
|
mEventReceiverFactory = eventReceiverFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -103,42 +137,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createWindowDecoration(
|
public boolean onTaskOpening(
|
||||||
ActivityManager.RunningTaskInfo taskInfo,
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
SurfaceControl taskSurface,
|
SurfaceControl taskSurface,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
if (!shouldShowWindowDecor(taskInfo)) return false;
|
if (!shouldShowWindowDecor(taskInfo)) return false;
|
||||||
CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
|
||||||
if (oldDecoration != null) {
|
|
||||||
// close the old decoration if it exists to avoid two window decorations being added
|
|
||||||
oldDecoration.close();
|
|
||||||
}
|
|
||||||
final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
|
|
||||||
mContext,
|
|
||||||
mDisplayController,
|
|
||||||
mTaskOrganizer,
|
|
||||||
taskInfo,
|
|
||||||
taskSurface,
|
|
||||||
mMainHandler,
|
|
||||||
mMainChoreographer,
|
|
||||||
mSyncQueue);
|
|
||||||
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
|
|
||||||
|
|
||||||
TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration,
|
|
||||||
mDragStartListener);
|
|
||||||
CaptionTouchEventListener touchEventListener =
|
|
||||||
new CaptionTouchEventListener(taskInfo, taskPositioner,
|
|
||||||
windowDecoration.getDragDetector());
|
|
||||||
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
|
||||||
windowDecoration.setDragResizeCallback(taskPositioner);
|
|
||||||
setupWindowDecorationForTransition(taskInfo, startT, finishT);
|
|
||||||
if (mInputMonitor == null) {
|
|
||||||
mInputMonitor = InputManager.getInstance().monitorGestureInput(
|
|
||||||
"caption-touch", mContext.getDisplayId());
|
|
||||||
mEventReceiver = new EventReceiver(
|
|
||||||
mInputMonitor.getInputChannel(), Looper.myLooper());
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,25 +156,45 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setupWindowDecorationForTransition(
|
public void onTaskChanging(
|
||||||
|
RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
SurfaceControl.Transaction startT,
|
||||||
|
SurfaceControl.Transaction finishT) {
|
||||||
|
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
||||||
|
|
||||||
|
if (!shouldShowWindowDecor(taskInfo)) {
|
||||||
|
if (decoration != null) {
|
||||||
|
destroyWindowDecoration(taskInfo);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoration == null) {
|
||||||
|
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
|
||||||
|
} else {
|
||||||
|
decoration.relayout(taskInfo, startT, finishT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskClosing(
|
||||||
RunningTaskInfo taskInfo,
|
RunningTaskInfo taskInfo,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT) {
|
SurfaceControl.Transaction finishT) {
|
||||||
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
||||||
if (decoration == null) return false;
|
if (decoration == null) return;
|
||||||
|
|
||||||
decoration.relayout(taskInfo, startT, finishT);
|
decoration.relayout(taskInfo, startT, finishT);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean destroyWindowDecoration(RunningTaskInfo taskInfo) {
|
public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
|
||||||
final CaptionWindowDecoration decoration =
|
final CaptionWindowDecoration decoration =
|
||||||
mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
|
mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
|
||||||
if (decoration == null) return false;
|
if (decoration == null) return;
|
||||||
|
|
||||||
decoration.close();
|
decoration.close();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CaptionTouchEventListener implements
|
private class CaptionTouchEventListener implements
|
||||||
@@ -217,6 +242,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
decoration.setButtonVisibility();
|
decoration.setButtonVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void injectBackKey() {
|
private void injectBackKey() {
|
||||||
sendBackEvent(KeyEvent.ACTION_DOWN);
|
sendBackEvent(KeyEvent.ACTION_DOWN);
|
||||||
sendBackEvent(KeyEvent.ACTION_UP);
|
sendBackEvent(KeyEvent.ACTION_UP);
|
||||||
@@ -302,7 +328,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InputEventReceiver to listen for touch input outside of caption bounds
|
// InputEventReceiver to listen for touch input outside of caption bounds
|
||||||
private class EventReceiver extends InputEventReceiver {
|
class EventReceiver extends InputEventReceiver {
|
||||||
EventReceiver(InputChannel channel, Looper looper) {
|
EventReceiver(InputChannel channel, Looper looper) {
|
||||||
super(channel, looper);
|
super(channel, looper);
|
||||||
}
|
}
|
||||||
@@ -318,8 +344,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EventReceiverFactory {
|
||||||
|
EventReceiver create(InputChannel channel, Looper looper) {
|
||||||
|
return new EventReceiver(channel, looper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle MotionEvents relevant to focused task's caption that don't directly touch it
|
* Handle MotionEvents relevant to focused task's caption that don't directly touch it
|
||||||
|
*
|
||||||
* @param ev the {@link MotionEvent} received by {@link EventReceiver}
|
* @param ev the {@link MotionEvent} received by {@link EventReceiver}
|
||||||
*/
|
*/
|
||||||
private void handleReceivedMotionEvent(MotionEvent ev) {
|
private void handleReceivedMotionEvent(MotionEvent ev) {
|
||||||
@@ -401,7 +434,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
return focusedDecor;
|
return focusedDecor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
|
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
|
||||||
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
|
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
|
||||||
return DesktopModeStatus.IS_SUPPORTED
|
return DesktopModeStatus.IS_SUPPORTED
|
||||||
@@ -410,7 +442,47 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
|
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DragStartListenerImpl implements TaskPositioner.DragStartListener{
|
private void createWindowDecoration(
|
||||||
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
SurfaceControl.Transaction startT,
|
||||||
|
SurfaceControl.Transaction finishT) {
|
||||||
|
CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
||||||
|
if (oldDecoration != null) {
|
||||||
|
// close the old decoration if it exists to avoid two window decorations being added
|
||||||
|
oldDecoration.close();
|
||||||
|
}
|
||||||
|
final CaptionWindowDecoration windowDecoration =
|
||||||
|
mCaptionWindowDecorFactory.create(
|
||||||
|
mContext,
|
||||||
|
mDisplayController,
|
||||||
|
mTaskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
taskSurface,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mSyncQueue);
|
||||||
|
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
|
||||||
|
|
||||||
|
TaskPositioner taskPositioner =
|
||||||
|
new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
|
||||||
|
CaptionTouchEventListener touchEventListener =
|
||||||
|
new CaptionTouchEventListener(
|
||||||
|
taskInfo, taskPositioner, windowDecoration.getDragDetector());
|
||||||
|
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
||||||
|
windowDecoration.setDragResizeCallback(taskPositioner);
|
||||||
|
windowDecoration.relayout(taskInfo, startT, finishT);
|
||||||
|
if (mInputMonitor == null) {
|
||||||
|
InputManager inputManager = mInputManagerSupplier.get();
|
||||||
|
mInputMonitor =
|
||||||
|
inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId());
|
||||||
|
mEventReceiver =
|
||||||
|
mEventReceiverFactory.create(
|
||||||
|
mInputMonitor.getInputChannel(), Looper.myLooper());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DragStartListenerImpl implements TaskPositioner.DragStartListener {
|
||||||
@Override
|
@Override
|
||||||
public void onDragStart(int taskId) {
|
public void onDragStart(int taskId) {
|
||||||
mWindowDecorByTaskId.get(taskId).closeHandleMenu();
|
mWindowDecorByTaskId.get(taskId).closeHandleMenu();
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
|
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
|
||||||
* {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close button.
|
* {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close
|
||||||
|
* button.
|
||||||
*
|
*
|
||||||
* The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
|
* The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
|
||||||
*/
|
*/
|
||||||
@@ -242,7 +243,6 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the visibility of buttons and color of caption based on desktop mode status
|
* Sets the visibility of buttons and color of caption based on desktop mode status
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void setButtonVisibility() {
|
void setButtonVisibility() {
|
||||||
mDesktopActive = DesktopModeStatus.isActive(mContext);
|
mDesktopActive = DesktopModeStatus.isActive(mContext);
|
||||||
@@ -313,6 +313,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close an open handle menu if input is outside of menu coordinates
|
* Close an open handle menu if input is outside of menu coordinates
|
||||||
|
*
|
||||||
* @param ev the tapped point to compare against
|
* @param ev the tapped point to compare against
|
||||||
*/
|
*/
|
||||||
void closeHandleMenuIfNeeded(MotionEvent ev) {
|
void closeHandleMenuIfNeeded(MotionEvent ev) {
|
||||||
@@ -329,6 +330,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Offset the coordinates of a {@link MotionEvent} to be in the same coordinate space as caption
|
* Offset the coordinates of a {@link MotionEvent} to be in the same coordinate space as caption
|
||||||
|
*
|
||||||
* @param ev the {@link MotionEvent} to offset
|
* @param ev the {@link MotionEvent} to offset
|
||||||
* @return the point of the input in local space
|
* @return the point of the input in local space
|
||||||
*/
|
*/
|
||||||
@@ -343,6 +345,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a passed MotionEvent is in a view in caption
|
* Determine if a passed MotionEvent is in a view in caption
|
||||||
|
*
|
||||||
* @param ev the {@link MotionEvent} to check
|
* @param ev the {@link MotionEvent} to check
|
||||||
* @param layoutId the id of the view
|
* @param layoutId the id of the view
|
||||||
* @return {@code true} if event is inside the specified view, {@code false} if not
|
* @return {@code true} if event is inside the specified view, {@code false} if not
|
||||||
@@ -363,6 +366,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
* Check a passed MotionEvent if a click has occurred on any button on this caption
|
* Check a passed MotionEvent if a click has occurred on any button on this caption
|
||||||
* Note this should only be called when a regular onClick is not possible
|
* Note this should only be called when a regular onClick is not possible
|
||||||
* (i.e. the button was clicked through status bar layer)
|
* (i.e. the button was clicked through status bar layer)
|
||||||
|
*
|
||||||
* @param ev the MotionEvent to compare
|
* @param ev the MotionEvent to compare
|
||||||
*/
|
*/
|
||||||
void checkClickEvent(MotionEvent ev) {
|
void checkClickEvent(MotionEvent ev) {
|
||||||
@@ -399,4 +403,27 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
closeHandleMenu();
|
closeHandleMenu();
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Factory {
|
||||||
|
|
||||||
|
CaptionWindowDecoration create(
|
||||||
|
Context context,
|
||||||
|
DisplayController displayController,
|
||||||
|
ShellTaskOrganizer taskOrganizer,
|
||||||
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
Handler handler,
|
||||||
|
Choreographer choreographer,
|
||||||
|
SyncTransactionQueue syncQueue) {
|
||||||
|
return new CaptionWindowDecoration(
|
||||||
|
context,
|
||||||
|
displayController,
|
||||||
|
taskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
taskSurface,
|
||||||
|
handler,
|
||||||
|
choreographer,
|
||||||
|
syncQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
|||||||
* servers.
|
* servers.
|
||||||
*/
|
*/
|
||||||
public interface WindowDecorViewModel {
|
public interface WindowDecorViewModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the transition starter that starts freeform task transitions.
|
* Sets the transition starter that starts freeform task transitions.
|
||||||
*
|
*
|
||||||
@@ -37,8 +36,8 @@ public interface WindowDecorViewModel {
|
|||||||
void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
|
void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a window decoration for the given task.
|
* Creates a window decoration for the given task. Can be {@code null} for Fullscreen tasks but
|
||||||
* Can be {@code null} for Fullscreen tasks but not Freeform ones.
|
* not Freeform ones.
|
||||||
*
|
*
|
||||||
* @param taskInfo the initial task info of the task
|
* @param taskInfo the initial task info of the task
|
||||||
* @param taskSurface the surface of the task
|
* @param taskSurface the surface of the task
|
||||||
@@ -46,7 +45,7 @@ public interface WindowDecorViewModel {
|
|||||||
* @param finishT the finish transaction to restore states after the transition
|
* @param finishT the finish transaction to restore states after the transition
|
||||||
* @return {@code true} if window decoration was created, {@code false} otherwise
|
* @return {@code true} if window decoration was created, {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean createWindowDecoration(
|
boolean onTaskOpening(
|
||||||
ActivityManager.RunningTaskInfo taskInfo,
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
SurfaceControl taskSurface,
|
SurfaceControl taskSurface,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
@@ -54,7 +53,7 @@ public interface WindowDecorViewModel {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies a task info update on the given task, with the window decoration created previously
|
* Notifies a task info update on the given task, with the window decoration created previously
|
||||||
* for this task by {@link #createWindowDecoration}.
|
* for this task by {@link #onTaskOpening}.
|
||||||
*
|
*
|
||||||
* @param taskInfo the new task info of the task
|
* @param taskInfo the new task info of the task
|
||||||
*/
|
*/
|
||||||
@@ -62,13 +61,29 @@ public interface WindowDecorViewModel {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies a transition is about to start about the given task to give the window decoration a
|
* Notifies a transition is about to start about the given task to give the window decoration a
|
||||||
* chance to prepare for this transition.
|
* chance to prepare for this transition. Unlike {@link #onTaskInfoChanged}, this method creates
|
||||||
|
* a window decoration if one does not exist but is required.
|
||||||
*
|
*
|
||||||
|
* @param taskInfo the initial task info of the task
|
||||||
|
* @param taskSurface the surface of the task
|
||||||
* @param startT the start transaction to be applied before the transition
|
* @param startT the start transaction to be applied before the transition
|
||||||
* @param finishT the finish transaction to restore states after the transition
|
* @param finishT the finish transaction to restore states after the transition
|
||||||
* @return {@code true} if window decoration exists, {@code false} otherwise
|
|
||||||
*/
|
*/
|
||||||
boolean setupWindowDecorationForTransition(
|
void onTaskChanging(
|
||||||
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
SurfaceControl.Transaction startT,
|
||||||
|
SurfaceControl.Transaction finishT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies that the given task is about to close to give the window decoration a chance to
|
||||||
|
* prepare for this transition.
|
||||||
|
*
|
||||||
|
* @param taskInfo the initial task info of the task
|
||||||
|
* @param startT the start transaction to be applied before the transition
|
||||||
|
* @param finishT the finish transaction to restore states after the transition
|
||||||
|
*/
|
||||||
|
void onTaskClosing(
|
||||||
ActivityManager.RunningTaskInfo taskInfo,
|
ActivityManager.RunningTaskInfo taskInfo,
|
||||||
SurfaceControl.Transaction startT,
|
SurfaceControl.Transaction startT,
|
||||||
SurfaceControl.Transaction finishT);
|
SurfaceControl.Transaction finishT);
|
||||||
@@ -77,7 +92,6 @@ public interface WindowDecorViewModel {
|
|||||||
* Destroys the window decoration of the give task.
|
* Destroys the window decoration of the give task.
|
||||||
*
|
*
|
||||||
* @param taskInfo the info of the task
|
* @param taskInfo the info of the task
|
||||||
* @return {@code true} if window decoration was destroyed, {@code false} otherwise
|
|
||||||
*/
|
*/
|
||||||
boolean destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
|
void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ public class FreeformTaskTransitionObserverTest {
|
|||||||
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
|
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
|
||||||
mTransitionObserver.onTransitionStarting(transition);
|
mTransitionObserver.onTransitionStarting(transition);
|
||||||
|
|
||||||
verify(mWindowDecorViewModel).createWindowDecoration(
|
verify(mWindowDecorViewModel).onTaskOpening(
|
||||||
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
change.getTaskInfo(), change.getLeash(), startT, finishT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ public class FreeformTaskTransitionObserverTest {
|
|||||||
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
|
mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
|
||||||
mTransitionObserver.onTransitionStarting(transition);
|
mTransitionObserver.onTransitionStarting(transition);
|
||||||
|
|
||||||
verify(mWindowDecorViewModel).setupWindowDecorationForTransition(
|
verify(mWindowDecorViewModel).onTaskClosing(
|
||||||
change.getTaskInfo(), startT, finishT);
|
change.getTaskInfo(), startT, finishT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.windowdecor;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||||
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.hardware.input.InputManager;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.view.Choreographer;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.InputChannel;
|
||||||
|
import android.view.InputMonitor;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.ShellTestCase;
|
||||||
|
import com.android.wm.shell.TestRunningTaskInfoBuilder;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.desktopmode.DesktopModeController;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/** Tests of {@link CaptionWindowDecorViewModel} */
|
||||||
|
@SmallTest
|
||||||
|
public class CaptionWindowDecorViewModelTests extends ShellTestCase {
|
||||||
|
@Mock private CaptionWindowDecoration mCaptionWindowDecoration;
|
||||||
|
|
||||||
|
@Mock private CaptionWindowDecoration.Factory mCaptionWindowDecorFactory;
|
||||||
|
|
||||||
|
@Mock private Handler mMainHandler;
|
||||||
|
|
||||||
|
@Mock private Choreographer mMainChoreographer;
|
||||||
|
|
||||||
|
@Mock private ShellTaskOrganizer mTaskOrganizer;
|
||||||
|
|
||||||
|
@Mock private DisplayController mDisplayController;
|
||||||
|
|
||||||
|
@Mock private SyncTransactionQueue mSyncQueue;
|
||||||
|
|
||||||
|
@Mock private DesktopModeController mDesktopModeController;
|
||||||
|
|
||||||
|
@Mock private InputMonitor mInputMonitor;
|
||||||
|
|
||||||
|
@Mock private InputChannel mInputChannel;
|
||||||
|
|
||||||
|
@Mock private CaptionWindowDecorViewModel.EventReceiverFactory mEventReceiverFactory;
|
||||||
|
|
||||||
|
@Mock private CaptionWindowDecorViewModel.EventReceiver mEventReceiver;
|
||||||
|
|
||||||
|
@Mock private InputManager mInputManager;
|
||||||
|
|
||||||
|
private final List<InputManager> mMockInputManagers = new ArrayList<>();
|
||||||
|
|
||||||
|
private CaptionWindowDecorViewModel mCaptionWindowDecorViewModel;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mMockInputManagers.add(mInputManager);
|
||||||
|
|
||||||
|
mCaptionWindowDecorViewModel =
|
||||||
|
new CaptionWindowDecorViewModel(
|
||||||
|
mContext,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mTaskOrganizer,
|
||||||
|
mDisplayController,
|
||||||
|
mSyncQueue,
|
||||||
|
mDesktopModeController,
|
||||||
|
mCaptionWindowDecorFactory,
|
||||||
|
new MockObjectSupplier<>(mMockInputManagers, () -> mock(InputManager.class)));
|
||||||
|
mCaptionWindowDecorViewModel.setEventReceiverFactory(mEventReceiverFactory);
|
||||||
|
|
||||||
|
doReturn(mCaptionWindowDecoration)
|
||||||
|
.when(mCaptionWindowDecorFactory)
|
||||||
|
.create(any(), any(), any(), any(), any(), any(), any(), any());
|
||||||
|
|
||||||
|
when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor);
|
||||||
|
when(mEventReceiverFactory.create(any(), any())).thenReturn(mEventReceiver);
|
||||||
|
when(mInputMonitor.getInputChannel()).thenReturn(mInputChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCaptionOnChangeTransitionWhenNecessary() throws Exception {
|
||||||
|
Looper.prepare();
|
||||||
|
final int taskId = 1;
|
||||||
|
final ActivityManager.RunningTaskInfo taskInfo =
|
||||||
|
createTaskInfo(taskId, WINDOWING_MODE_FREEFORM);
|
||||||
|
SurfaceControl surfaceControl = mock(SurfaceControl.class);
|
||||||
|
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
|
||||||
|
final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
|
||||||
|
GrantPermissionRule.grant(android.Manifest.permission.MONITOR_INPUT);
|
||||||
|
|
||||||
|
mCaptionWindowDecorViewModel.onTaskOpening(taskInfo, surfaceControl, startT, finishT);
|
||||||
|
verify(mCaptionWindowDecorFactory)
|
||||||
|
.create(
|
||||||
|
mContext,
|
||||||
|
mDisplayController,
|
||||||
|
mTaskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
surfaceControl,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mSyncQueue);
|
||||||
|
|
||||||
|
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
|
||||||
|
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
|
||||||
|
mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
|
||||||
|
verify(mCaptionWindowDecoration).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCaptionOnChangeTransitionWhenNecessary() throws Exception {
|
||||||
|
final int taskId = 1;
|
||||||
|
final ActivityManager.RunningTaskInfo taskInfo =
|
||||||
|
createTaskInfo(taskId, WINDOWING_MODE_UNDEFINED);
|
||||||
|
SurfaceControl surfaceControl = mock(SurfaceControl.class);
|
||||||
|
final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
|
||||||
|
final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
|
||||||
|
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
|
||||||
|
|
||||||
|
mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
|
||||||
|
|
||||||
|
verify(mCaptionWindowDecorFactory, never())
|
||||||
|
.create(
|
||||||
|
mContext,
|
||||||
|
mDisplayController,
|
||||||
|
mTaskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
surfaceControl,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mSyncQueue);
|
||||||
|
|
||||||
|
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||||
|
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
|
||||||
|
|
||||||
|
mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
|
||||||
|
|
||||||
|
verify(mCaptionWindowDecorFactory)
|
||||||
|
.create(
|
||||||
|
mContext,
|
||||||
|
mDisplayController,
|
||||||
|
mTaskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
surfaceControl,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mSyncQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
|
||||||
|
ActivityManager.RunningTaskInfo taskInfo =
|
||||||
|
new TestRunningTaskInfoBuilder()
|
||||||
|
.setDisplayId(Display.DEFAULT_DISPLAY)
|
||||||
|
.setVisible(true)
|
||||||
|
.build();
|
||||||
|
taskInfo.taskId = taskId;
|
||||||
|
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
|
||||||
|
return taskInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockObjectSupplier<T> implements Supplier<T> {
|
||||||
|
private final List<T> mObjects;
|
||||||
|
private final Supplier<T> mDefaultSupplier;
|
||||||
|
private int mNumOfCalls = 0;
|
||||||
|
|
||||||
|
private MockObjectSupplier(List<T> objects, Supplier<T> defaultSupplier) {
|
||||||
|
mObjects = objects;
|
||||||
|
mDefaultSupplier = defaultSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get() {
|
||||||
|
final T mock =
|
||||||
|
mNumOfCalls < mObjects.size() ? mObjects.get(mNumOfCalls)
|
||||||
|
: mDefaultSupplier.get();
|
||||||
|
++mNumOfCalls;
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user