Merge "Add full-width caption on Shell." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
12fb8ad349
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2023 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.
|
||||||
|
-->
|
||||||
|
<shape android:shape="rectangle"
|
||||||
|
android:tintMode="multiply"
|
||||||
|
android:tint="@color/decor_title_color"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="32.0dp"
|
||||||
android:height="24dp"
|
android:height="32.0dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="32.0"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="32.0"
|
||||||
android:tint="@color/decor_button_dark_color">
|
android:tint="@color/decor_button_dark_color">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white" android:pathData="M6,21V19H18V21Z"/>
|
android:fillColor="@android:color/white" android:pathData="M6,21V19H18V21Z"/>
|
||||||
|
|||||||
56
libs/WindowManager/Shell/res/layout/caption_window_decor.xml
Normal file
56
libs/WindowManager/Shell/res/layout/caption_window_decor.xml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2023 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.
|
||||||
|
-->
|
||||||
|
<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/caption"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:background="@drawable/caption_decor_title">
|
||||||
|
<Button
|
||||||
|
style="@style/CaptionButtonStyle"
|
||||||
|
android:id="@+id/back_button"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:contentDescription="@string/back_button_text"
|
||||||
|
android:background="@drawable/decor_back_button_dark"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<Space
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:elevation="2dp"/>
|
||||||
|
<Button
|
||||||
|
style="@style/CaptionButtonStyle"
|
||||||
|
android:id="@+id/minimize_window"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:contentDescription="@string/minimize_button_text"
|
||||||
|
android:background="@drawable/decor_minimize_button_dark"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<Button
|
||||||
|
style="@style/CaptionButtonStyle"
|
||||||
|
android:id="@+id/maximize_window"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:contentDescription="@string/maximize_button_text"
|
||||||
|
android:background="@drawable/decor_maximize_button_dark"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<Button
|
||||||
|
style="@style/CaptionButtonStyle"
|
||||||
|
android:id="@+id/close_window"
|
||||||
|
android:contentDescription="@string/close_button_text"
|
||||||
|
android:background="@drawable/decor_close_button_dark"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
|
||||||
@@ -49,6 +49,7 @@ import com.android.wm.shell.common.TransactionPool;
|
|||||||
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
|
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
|
||||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||||
import com.android.wm.shell.desktopmode.DesktopModeController;
|
import com.android.wm.shell.desktopmode.DesktopModeController;
|
||||||
|
import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
||||||
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
|
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
|
||||||
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
||||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
@@ -93,6 +94,7 @@ import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
|
|||||||
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
|
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
|
||||||
import com.android.wm.shell.unfold.qualifier.UnfoldShellTransition;
|
import com.android.wm.shell.unfold.qualifier.UnfoldShellTransition;
|
||||||
import com.android.wm.shell.unfold.qualifier.UnfoldTransition;
|
import com.android.wm.shell.unfold.qualifier.UnfoldTransition;
|
||||||
|
import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
|
||||||
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
|
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
|
||||||
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
|
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
|
||||||
|
|
||||||
@@ -192,6 +194,7 @@ public abstract class WMShellModule {
|
|||||||
SyncTransactionQueue syncQueue,
|
SyncTransactionQueue syncQueue,
|
||||||
Optional<DesktopModeController> desktopModeController,
|
Optional<DesktopModeController> desktopModeController,
|
||||||
Optional<DesktopTasksController> desktopTasksController) {
|
Optional<DesktopTasksController> desktopTasksController) {
|
||||||
|
if (DesktopModeStatus.isAnyEnabled()) {
|
||||||
return new DesktopModeWindowDecorViewModel(
|
return new DesktopModeWindowDecorViewModel(
|
||||||
context,
|
context,
|
||||||
mainHandler,
|
mainHandler,
|
||||||
@@ -202,6 +205,14 @@ public abstract class WMShellModule {
|
|||||||
desktopModeController,
|
desktopModeController,
|
||||||
desktopTasksController);
|
desktopTasksController);
|
||||||
}
|
}
|
||||||
|
return new CaptionWindowDecorViewModel(
|
||||||
|
context,
|
||||||
|
mainHandler,
|
||||||
|
mainChoreographer,
|
||||||
|
taskOrganizer,
|
||||||
|
displayController,
|
||||||
|
syncQueue);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Freeform
|
// Freeform
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.WINDOWING_MODE_FREEFORM;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
|
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.Choreographer;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.View;
|
||||||
|
import android.window.WindowContainerToken;
|
||||||
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model for the window decoration with a caption and shadows. Works with
|
||||||
|
* {@link CaptionWindowDecoration}.
|
||||||
|
*/
|
||||||
|
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
||||||
|
private final ShellTaskOrganizer mTaskOrganizer;
|
||||||
|
private final Context mContext;
|
||||||
|
private final Handler mMainHandler;
|
||||||
|
private final Choreographer mMainChoreographer;
|
||||||
|
private final DisplayController mDisplayController;
|
||||||
|
private final SyncTransactionQueue mSyncQueue;
|
||||||
|
private TaskOperations mTaskOperations;
|
||||||
|
|
||||||
|
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
|
||||||
|
|
||||||
|
public CaptionWindowDecorViewModel(
|
||||||
|
Context context,
|
||||||
|
Handler mainHandler,
|
||||||
|
Choreographer mainChoreographer,
|
||||||
|
ShellTaskOrganizer taskOrganizer,
|
||||||
|
DisplayController displayController,
|
||||||
|
SyncTransactionQueue syncQueue) {
|
||||||
|
mContext = context;
|
||||||
|
mMainHandler = mainHandler;
|
||||||
|
mMainChoreographer = mainChoreographer;
|
||||||
|
mTaskOrganizer = taskOrganizer;
|
||||||
|
mDisplayController = displayController;
|
||||||
|
mSyncQueue = syncQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
|
||||||
|
mTaskOperations = new TaskOperations(transitionStarter, mContext, mSyncQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTaskOpening(
|
||||||
|
RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
SurfaceControl.Transaction startT,
|
||||||
|
SurfaceControl.Transaction finishT) {
|
||||||
|
if (!shouldShowWindowDecor(taskInfo)) return false;
|
||||||
|
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
|
||||||
|
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
||||||
|
|
||||||
|
if (decoration == null) return;
|
||||||
|
|
||||||
|
decoration.relayout(taskInfo);
|
||||||
|
setupCaptionColor(taskInfo, decoration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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,
|
||||||
|
SurfaceControl.Transaction startT,
|
||||||
|
SurfaceControl.Transaction finishT) {
|
||||||
|
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
|
||||||
|
if (decoration == null) return;
|
||||||
|
|
||||||
|
decoration.relayout(taskInfo, startT, finishT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
|
||||||
|
final CaptionWindowDecoration decoration =
|
||||||
|
mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
|
||||||
|
if (decoration == null) return;
|
||||||
|
|
||||||
|
decoration.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
|
||||||
|
int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
|
||||||
|
decoration.setCaptionColor(statusBarColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
|
||||||
|
return taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
|
||||||
|
|| (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
|
||||||
|
&& taskInfo.configuration.windowConfiguration.getDisplayWindowingMode()
|
||||||
|
== WINDOWING_MODE_FREEFORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createWindowDecoration(
|
||||||
|
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 =
|
||||||
|
new CaptionWindowDecoration(
|
||||||
|
mContext,
|
||||||
|
mDisplayController,
|
||||||
|
mTaskOrganizer,
|
||||||
|
taskInfo,
|
||||||
|
taskSurface,
|
||||||
|
mMainHandler,
|
||||||
|
mMainChoreographer,
|
||||||
|
mSyncQueue);
|
||||||
|
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
|
||||||
|
|
||||||
|
TaskPositioner taskPositioner =
|
||||||
|
new TaskPositioner(mTaskOrganizer, windowDecoration);
|
||||||
|
CaptionTouchEventListener touchEventListener =
|
||||||
|
new CaptionTouchEventListener(taskInfo, taskPositioner);
|
||||||
|
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
||||||
|
windowDecoration.setDragResizeCallback(taskPositioner);
|
||||||
|
windowDecoration.relayout(taskInfo, startT, finishT);
|
||||||
|
setupCaptionColor(taskInfo, windowDecoration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CaptionTouchEventListener implements
|
||||||
|
View.OnClickListener, View.OnTouchListener {
|
||||||
|
|
||||||
|
private final int mTaskId;
|
||||||
|
private final WindowContainerToken mTaskToken;
|
||||||
|
private final DragResizeCallback mDragResizeCallback;
|
||||||
|
|
||||||
|
private int mDragPointerId = -1;
|
||||||
|
|
||||||
|
private CaptionTouchEventListener(
|
||||||
|
RunningTaskInfo taskInfo,
|
||||||
|
DragResizeCallback dragResizeCallback) {
|
||||||
|
mTaskId = taskInfo.taskId;
|
||||||
|
mTaskToken = taskInfo.token;
|
||||||
|
mDragResizeCallback = dragResizeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
final int id = v.getId();
|
||||||
|
if (id == R.id.close_window) {
|
||||||
|
mTaskOperations.closeTask(mTaskToken);
|
||||||
|
} else if (id == R.id.back_button) {
|
||||||
|
mTaskOperations.injectBackKey();
|
||||||
|
} else if (id == R.id.minimize_window) {
|
||||||
|
mTaskOperations.minimizeTask(mTaskToken);
|
||||||
|
} else if (id == R.id.maximize_window) {
|
||||||
|
RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
|
||||||
|
mTaskOperations.maximizeTask(taskInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent e) {
|
||||||
|
if (v.getId() != R.id.caption) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
handleEventForMove(e);
|
||||||
|
|
||||||
|
if (e.getAction() != MotionEvent.ACTION_DOWN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
|
||||||
|
if (taskInfo.isFocused) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
wct.reorder(mTaskToken, true /* onTop */);
|
||||||
|
mSyncQueue.queue(wct);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param e {@link MotionEvent} to process
|
||||||
|
* @return {@code true} if a drag is happening; or {@code false} if it is not
|
||||||
|
*/
|
||||||
|
private void handleEventForMove(MotionEvent e) {
|
||||||
|
RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
|
||||||
|
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (e.getActionMasked()) {
|
||||||
|
case MotionEvent.ACTION_DOWN: {
|
||||||
|
mDragPointerId = e.getPointerId(0);
|
||||||
|
mDragResizeCallback.onDragResizeStart(
|
||||||
|
0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
|
||||||
|
mDragResizeCallback.onDragResizeMove(
|
||||||
|
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL: {
|
||||||
|
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
|
||||||
|
mDragResizeCallback.onDragResizeEnd(
|
||||||
|
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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 android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
|
import android.graphics.drawable.VectorDrawable;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.Choreographer;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
|
||||||
|
* {@link CaptionWindowDecorViewModel}. The caption bar contains a back button, minimize button,
|
||||||
|
* maximize button and close button.
|
||||||
|
*/
|
||||||
|
public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> {
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final Choreographer mChoreographer;
|
||||||
|
private final SyncTransactionQueue mSyncQueue;
|
||||||
|
|
||||||
|
private View.OnClickListener mOnCaptionButtonClickListener;
|
||||||
|
private View.OnTouchListener mOnCaptionTouchListener;
|
||||||
|
private DragResizeCallback mDragResizeCallback;
|
||||||
|
|
||||||
|
private DragResizeInputListener mDragResizeListener;
|
||||||
|
|
||||||
|
private RelayoutParams mRelayoutParams = new RelayoutParams();
|
||||||
|
private final RelayoutResult<WindowDecorLinearLayout> mResult =
|
||||||
|
new RelayoutResult<>();
|
||||||
|
|
||||||
|
private DragDetector mDragDetector;
|
||||||
|
|
||||||
|
CaptionWindowDecoration(
|
||||||
|
Context context,
|
||||||
|
DisplayController displayController,
|
||||||
|
ShellTaskOrganizer taskOrganizer,
|
||||||
|
RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl taskSurface,
|
||||||
|
Handler handler,
|
||||||
|
Choreographer choreographer,
|
||||||
|
SyncTransactionQueue syncQueue) {
|
||||||
|
super(context, displayController, taskOrganizer, taskInfo, taskSurface);
|
||||||
|
|
||||||
|
mHandler = handler;
|
||||||
|
mChoreographer = choreographer;
|
||||||
|
mSyncQueue = syncQueue;
|
||||||
|
mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCaptionListeners(
|
||||||
|
View.OnClickListener onCaptionButtonClickListener,
|
||||||
|
View.OnTouchListener onCaptionTouchListener) {
|
||||||
|
mOnCaptionButtonClickListener = onCaptionButtonClickListener;
|
||||||
|
mOnCaptionTouchListener = onCaptionTouchListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDragResizeCallback(DragResizeCallback dragResizeCallback) {
|
||||||
|
mDragResizeCallback = dragResizeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void relayout(RunningTaskInfo taskInfo) {
|
||||||
|
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||||
|
relayout(taskInfo, t, t);
|
||||||
|
mSyncQueue.runInSync(transaction -> {
|
||||||
|
transaction.merge(t);
|
||||||
|
t.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void relayout(RunningTaskInfo taskInfo,
|
||||||
|
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
|
||||||
|
final int shadowRadiusID = taskInfo.isFocused
|
||||||
|
? R.dimen.freeform_decor_shadow_focused_thickness
|
||||||
|
: R.dimen.freeform_decor_shadow_unfocused_thickness;
|
||||||
|
final boolean isFreeform =
|
||||||
|
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||||
|
final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
|
||||||
|
|
||||||
|
WindowDecorLinearLayout oldRootView = mResult.mRootView;
|
||||||
|
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
|
||||||
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
|
||||||
|
int outsetLeftId = R.dimen.freeform_resize_handle;
|
||||||
|
int outsetTopId = R.dimen.freeform_resize_handle;
|
||||||
|
int outsetRightId = R.dimen.freeform_resize_handle;
|
||||||
|
int outsetBottomId = R.dimen.freeform_resize_handle;
|
||||||
|
|
||||||
|
mRelayoutParams.reset();
|
||||||
|
mRelayoutParams.mRunningTaskInfo = taskInfo;
|
||||||
|
mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
|
||||||
|
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
|
||||||
|
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
|
||||||
|
if (isDragResizeable) {
|
||||||
|
mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
|
||||||
|
taskInfo = null; // Clear it just in case we use it accidentally
|
||||||
|
|
||||||
|
mTaskOrganizer.applyTransaction(wct);
|
||||||
|
|
||||||
|
if (mResult.mRootView == null) {
|
||||||
|
// This means something blocks the window decor from showing, e.g. the task is hidden.
|
||||||
|
// Nothing is set up in this case including the decoration surface.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (oldRootView != mResult.mRootView) {
|
||||||
|
setupRootView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDragResizeable) {
|
||||||
|
closeDragResizeListener();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) {
|
||||||
|
closeDragResizeListener();
|
||||||
|
mDragResizeListener = new DragResizeInputListener(
|
||||||
|
mContext,
|
||||||
|
mHandler,
|
||||||
|
mChoreographer,
|
||||||
|
mDisplay.getDisplayId(),
|
||||||
|
mDecorationContainerSurface,
|
||||||
|
mDragResizeCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();
|
||||||
|
mDragDetector.setTouchSlop(touchSlop);
|
||||||
|
|
||||||
|
int resize_handle = mResult.mRootView.getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.freeform_resize_handle);
|
||||||
|
int resize_corner = mResult.mRootView.getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.freeform_resize_corner);
|
||||||
|
mDragResizeListener.setGeometry(
|
||||||
|
mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up listeners when a new root view is created.
|
||||||
|
*/
|
||||||
|
private void setupRootView() {
|
||||||
|
View caption = mResult.mRootView.findViewById(R.id.caption);
|
||||||
|
caption.setOnTouchListener(mOnCaptionTouchListener);
|
||||||
|
View close = caption.findViewById(R.id.close_window);
|
||||||
|
close.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
|
View back = caption.findViewById(R.id.back_button);
|
||||||
|
back.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
|
View minimize = caption.findViewById(R.id.minimize_window);
|
||||||
|
minimize.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
|
View maximize = caption.findViewById(R.id.maximize_window);
|
||||||
|
maximize.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCaptionColor(int captionColor) {
|
||||||
|
if (mResult.mRootView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
View caption = mResult.mRootView.findViewById(R.id.caption);
|
||||||
|
GradientDrawable captionDrawable = (GradientDrawable) caption.getBackground();
|
||||||
|
captionDrawable.setColor(captionColor);
|
||||||
|
|
||||||
|
int buttonTintColorRes =
|
||||||
|
Color.valueOf(captionColor).luminance() < 0.5
|
||||||
|
? R.color.decor_button_light_color
|
||||||
|
: R.color.decor_button_dark_color;
|
||||||
|
ColorStateList buttonTintColor =
|
||||||
|
caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */);
|
||||||
|
|
||||||
|
View back = caption.findViewById(R.id.back_button);
|
||||||
|
VectorDrawable backBackground = (VectorDrawable) back.getBackground();
|
||||||
|
backBackground.setTintList(buttonTintColor);
|
||||||
|
|
||||||
|
View minimize = caption.findViewById(R.id.minimize_window);
|
||||||
|
VectorDrawable minimizeBackground = (VectorDrawable) minimize.getBackground();
|
||||||
|
minimizeBackground.setTintList(buttonTintColor);
|
||||||
|
|
||||||
|
View maximize = caption.findViewById(R.id.maximize_window);
|
||||||
|
VectorDrawable maximizeBackground = (VectorDrawable) maximize.getBackground();
|
||||||
|
maximizeBackground.setTintList(buttonTintColor);
|
||||||
|
|
||||||
|
View close = caption.findViewById(R.id.close_window);
|
||||||
|
VectorDrawable closeBackground = (VectorDrawable) close.getBackground();
|
||||||
|
closeBackground.setTintList(buttonTintColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeDragResizeListener() {
|
||||||
|
if (mDragResizeListener == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDragResizeListener.close();
|
||||||
|
mDragResizeListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
closeDragResizeListener();
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,17 +27,12 @@ import android.content.Context;
|
|||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
import android.view.InputChannel;
|
import android.view.InputChannel;
|
||||||
import android.view.InputDevice;
|
|
||||||
import android.view.InputEvent;
|
import android.view.InputEvent;
|
||||||
import android.view.InputEventReceiver;
|
import android.view.InputEventReceiver;
|
||||||
import android.view.InputMonitor;
|
import android.view.InputMonitor;
|
||||||
import android.view.KeyCharacterMap;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -55,7 +50,6 @@ import com.android.wm.shell.desktopmode.DesktopModeController;
|
|||||||
import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
||||||
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
||||||
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -85,6 +79,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
new SparseArray<>();
|
new SparseArray<>();
|
||||||
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
|
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
|
||||||
private InputMonitorFactory mInputMonitorFactory;
|
private InputMonitorFactory mInputMonitorFactory;
|
||||||
|
private TaskOperations mTaskOperations;
|
||||||
|
|
||||||
public DesktopModeWindowDecorViewModel(
|
public DesktopModeWindowDecorViewModel(
|
||||||
Context context,
|
Context context,
|
||||||
@@ -136,7 +131,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
|
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
|
||||||
mTransitionStarter = transitionStarter;
|
mTaskOperations = new TaskOperations(transitionStarter, mContext, mSyncQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -210,7 +205,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CaptionTouchEventListener implements
|
private class DesktopModeTouchEventListener implements
|
||||||
View.OnClickListener, View.OnTouchListener {
|
View.OnClickListener, View.OnTouchListener {
|
||||||
|
|
||||||
private final int mTaskId;
|
private final int mTaskId;
|
||||||
@@ -220,7 +215,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
|
|
||||||
private int mDragPointerId = -1;
|
private int mDragPointerId = -1;
|
||||||
|
|
||||||
private CaptionTouchEventListener(
|
private DesktopModeTouchEventListener(
|
||||||
RunningTaskInfo taskInfo,
|
RunningTaskInfo taskInfo,
|
||||||
DragResizeCallback dragResizeCallback,
|
DragResizeCallback dragResizeCallback,
|
||||||
DragDetector dragDetector) {
|
DragDetector dragDetector) {
|
||||||
@@ -235,15 +230,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
|
DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
|
||||||
final int id = v.getId();
|
final int id = v.getId();
|
||||||
if (id == R.id.close_window) {
|
if (id == R.id.close_window) {
|
||||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
mTaskOperations.closeTask(mTaskToken);
|
||||||
wct.removeTask(mTaskToken);
|
|
||||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
|
||||||
mTransitionStarter.startRemoveTransition(wct);
|
|
||||||
} else {
|
|
||||||
mSyncQueue.queue(wct);
|
|
||||||
}
|
|
||||||
} else if (id == R.id.back_button) {
|
} else if (id == R.id.back_button) {
|
||||||
injectBackKey();
|
mTaskOperations.injectBackKey();
|
||||||
} else if (id == R.id.caption_handle) {
|
} else if (id == R.id.caption_handle) {
|
||||||
decoration.createHandleMenu();
|
decoration.createHandleMenu();
|
||||||
} else if (id == R.id.desktop_button) {
|
} else if (id == R.id.desktop_button) {
|
||||||
@@ -258,25 +247,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void injectBackKey() {
|
|
||||||
sendBackEvent(KeyEvent.ACTION_DOWN);
|
|
||||||
sendBackEvent(KeyEvent.ACTION_UP);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendBackEvent(int action) {
|
|
||||||
final long when = SystemClock.uptimeMillis();
|
|
||||||
final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK,
|
|
||||||
0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD,
|
|
||||||
0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
|
|
||||||
InputDevice.SOURCE_KEYBOARD);
|
|
||||||
|
|
||||||
ev.setDisplayId(mContext.getDisplay().getDisplayId());
|
|
||||||
if (!InputManager.getInstance()
|
|
||||||
.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
|
|
||||||
Log.e(TAG, "Inject input event fail");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent e) {
|
public boolean onTouch(View v, MotionEvent e) {
|
||||||
boolean isDrag = false;
|
boolean isDrag = false;
|
||||||
@@ -590,8 +560,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
|
|
||||||
TaskPositioner taskPositioner =
|
TaskPositioner taskPositioner =
|
||||||
new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
|
new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
|
||||||
CaptionTouchEventListener touchEventListener =
|
DesktopModeTouchEventListener touchEventListener =
|
||||||
new CaptionTouchEventListener(
|
new DesktopModeTouchEventListener(
|
||||||
taskInfo, taskPositioner, windowDecoration.getDragDetector());
|
taskInfo, taskPositioner, windowDecoration.getDragDetector());
|
||||||
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
||||||
windowDecoration.setDragResizeCallback(taskPositioner);
|
windowDecoration.setDragResizeCallback(taskPositioner);
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.WINDOWING_MODE_FREEFORM;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||||
|
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.hardware.input.InputManager;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.InputDevice;
|
||||||
|
import android.view.KeyCharacterMap;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.window.WindowContainerToken;
|
||||||
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
|
||||||
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to handle task operations performed on a window decoration.
|
||||||
|
*/
|
||||||
|
class TaskOperations {
|
||||||
|
private static final String TAG = "TaskOperations";
|
||||||
|
|
||||||
|
private final FreeformTaskTransitionStarter mTransitionStarter;
|
||||||
|
private final Context mContext;
|
||||||
|
private final SyncTransactionQueue mSyncQueue;
|
||||||
|
|
||||||
|
TaskOperations(FreeformTaskTransitionStarter transitionStarter, Context context,
|
||||||
|
SyncTransactionQueue syncQueue) {
|
||||||
|
mTransitionStarter = transitionStarter;
|
||||||
|
mContext = context;
|
||||||
|
mSyncQueue = syncQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void injectBackKey() {
|
||||||
|
sendBackEvent(KeyEvent.ACTION_DOWN);
|
||||||
|
sendBackEvent(KeyEvent.ACTION_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendBackEvent(int action) {
|
||||||
|
final long when = SystemClock.uptimeMillis();
|
||||||
|
final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK,
|
||||||
|
0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD,
|
||||||
|
0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
|
||||||
|
InputDevice.SOURCE_KEYBOARD);
|
||||||
|
|
||||||
|
ev.setDisplayId(mContext.getDisplay().getDisplayId());
|
||||||
|
if (!InputManager.getInstance()
|
||||||
|
.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
|
||||||
|
Log.e(TAG, "Inject input event fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeTask(WindowContainerToken taskToken) {
|
||||||
|
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
wct.removeTask(taskToken);
|
||||||
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
|
mTransitionStarter.startRemoveTransition(wct);
|
||||||
|
} else {
|
||||||
|
mSyncQueue.queue(wct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void minimizeTask(WindowContainerToken taskToken) {
|
||||||
|
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
wct.reorder(taskToken, false);
|
||||||
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
|
mTransitionStarter.startMinimizedModeTransition(wct);
|
||||||
|
} else {
|
||||||
|
mSyncQueue.queue(wct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void maximizeTask(RunningTaskInfo taskInfo) {
|
||||||
|
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
int targetWindowingMode = taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
|
||||||
|
? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_FREEFORM;
|
||||||
|
int displayWindowingMode =
|
||||||
|
taskInfo.configuration.windowConfiguration.getDisplayWindowingMode();
|
||||||
|
wct.setWindowingMode(taskInfo.token,
|
||||||
|
targetWindowingMode == displayWindowingMode
|
||||||
|
? WINDOWING_MODE_UNDEFINED : targetWindowingMode);
|
||||||
|
if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
|
||||||
|
wct.setBounds(taskInfo.token, null);
|
||||||
|
}
|
||||||
|
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||||
|
mTransitionStarter.startWindowingModeTransition(targetWindowingMode, wct);
|
||||||
|
} else {
|
||||||
|
mSyncQueue.queue(wct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,10 @@ class TaskPositioner implements DragResizeCallback {
|
|||||||
private int mCtrlType;
|
private int mCtrlType;
|
||||||
private DragStartListener mDragStartListener;
|
private DragStartListener mDragStartListener;
|
||||||
|
|
||||||
|
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration) {
|
||||||
|
this(taskOrganizer, windowDecoration, dragStartListener -> {});
|
||||||
|
}
|
||||||
|
|
||||||
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
|
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
|
||||||
DragStartListener dragStartListener) {
|
DragStartListener dragStartListener) {
|
||||||
mTaskOrganizer = taskOrganizer;
|
mTaskOrganizer = taskOrganizer;
|
||||||
|
|||||||
Reference in New Issue
Block a user