Add TV splitscreen menu
Add a splitscreen menu for TV allowing to change the focused task, swap the stages and exit the splitscreen mode by closing one of the stages. Bug: 242179031 Test: Enter the splitscreen mode. Send the corresponding broadcast to open the menu (adb shell am broadcast -a com.android.wm.shell.splitscreen.SHOW_MENU). Choose the needed action button and press it, open the menu again, etc. Press the back button on the menu control to hide the menu window. Change-Id: Iac17445414a190c91ccd407d67f0f8c29d6bd4bf
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="@dimen/tv_window_menu_icon_size"
|
||||||
|
android:height="@dimen/tv_window_menu_icon_size"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M17,4h3c1.1,0 2,0.9 2,2v2h-2L20,6h-3L17,4zM4,8L4,6h3L7,4L4,4c-1.1,0 -2,0.9 -2,2v2h2zM20,16v2h-3v2h3c1.1,0 2,-0.9 2,-2v-2h-2zM7,18L4,18v-2L2,16v2c0,1.1 0.9,2 2,2h3v-2zM18,8L6,8v8h12L18,8z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="@dimen/tv_window_menu_icon_size"
|
||||||
|
android:height="@dimen/tv_window_menu_icon_size"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"/>
|
||||||
|
</vector>
|
||||||
125
libs/WindowManager/Shell/res/layout/tv_split_menu_view.xml
Normal file
125
libs/WindowManager/Shell/res/layout/tv_split_menu_view.xml
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<!-- Layout for TvSplitMenuView -->
|
||||||
|
<com.android.wm.shell.splitscreen.tv.TvSplitMenuView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/tv_split_main_menu"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<com.android.wm.shell.common.TvWindowMenuActionButton
|
||||||
|
android:id="@+id/tv_split_main_menu_focus_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/tv_split_menu_ic_focus" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<com.android.wm.shell.common.TvWindowMenuActionButton
|
||||||
|
android:id="@+id/tv_split_main_menu_close_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/pip_ic_close_white" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.android.wm.shell.common.TvWindowMenuActionButton
|
||||||
|
android:id="@+id/tv_split_menu_swap_stages"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/tv_split_menu_ic_swap" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/tv_split_side_menu"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<com.android.wm.shell.common.TvWindowMenuActionButton
|
||||||
|
android:id="@+id/tv_split_side_menu_focus_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/tv_split_menu_ic_focus" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<com.android.wm.shell.common.TvWindowMenuActionButton
|
||||||
|
android:id="@+id/tv_split_side_menu_close_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/pip_ic_close_white" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.android.wm.shell.splitscreen.tv.TvSplitMenuView>
|
||||||
@@ -16,16 +16,32 @@
|
|||||||
|
|
||||||
package com.android.wm.shell.dagger;
|
package com.android.wm.shell.dagger;
|
||||||
|
|
||||||
import android.view.IWindowManager;
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import com.android.launcher3.icons.IconProvider;
|
||||||
|
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
import com.android.wm.shell.common.DisplayInsetsController;
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.common.SystemWindows;
|
||||||
import com.android.wm.shell.common.TransactionPool;
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||||
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
import com.android.wm.shell.splitscreen.tv.TvSplitScreenController;
|
||||||
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
|
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
|
||||||
import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm;
|
import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm;
|
||||||
|
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||||
|
import com.android.wm.shell.sysui.ShellController;
|
||||||
|
import com.android.wm.shell.sysui.ShellInit;
|
||||||
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -50,5 +66,33 @@ public class TvWMShellModule {
|
|||||||
@DynamicOverride
|
@DynamicOverride
|
||||||
static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() {
|
static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() {
|
||||||
return new TvStartingWindowTypeAlgorithm();
|
return new TvStartingWindowTypeAlgorithm();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
@DynamicOverride
|
||||||
|
static SplitScreenController provideSplitScreenController(Context context,
|
||||||
|
ShellInit shellInit,
|
||||||
|
ShellCommandHandler shellCommandHandler,
|
||||||
|
ShellController shellController,
|
||||||
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
|
SyncTransactionQueue syncQueue,
|
||||||
|
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
|
||||||
|
DisplayController displayController,
|
||||||
|
DisplayImeController displayImeController,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
|
DragAndDropController dragAndDropController,
|
||||||
|
Transitions transitions,
|
||||||
|
TransactionPool transactionPool,
|
||||||
|
IconProvider iconProvider,
|
||||||
|
Optional<RecentTasksController> recentTasks,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor,
|
||||||
|
Handler mainHandler,
|
||||||
|
SystemWindows systemWindows) {
|
||||||
|
return new TvSplitScreenController(context, shellInit, shellCommandHandler, shellController,
|
||||||
|
shellTaskOrganizer, syncQueue, rootTDAOrganizer, displayController,
|
||||||
|
displayImeController, displayInsetsController, dragAndDropController, transitions,
|
||||||
|
transactionPool, iconProvider, recentTasks, mainExecutor, mainHandler,
|
||||||
|
systemWindows);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,14 +213,18 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
|||||||
mShellController.addKeyguardChangeListener(this);
|
mShellController.addKeyguardChangeListener(this);
|
||||||
if (mStageCoordinator == null) {
|
if (mStageCoordinator == null) {
|
||||||
// TODO: Multi-display
|
// TODO: Multi-display
|
||||||
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
|
mStageCoordinator = createStageCoordinator();
|
||||||
mTaskOrganizer, mDisplayController, mDisplayImeController,
|
|
||||||
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
|
|
||||||
mIconProvider, mMainExecutor, mRecentTasksOptional);
|
|
||||||
}
|
}
|
||||||
mDragAndDropController.setSplitScreenController(this);
|
mDragAndDropController.setSplitScreenController(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected StageCoordinator createStageCoordinator() {
|
||||||
|
return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
|
||||||
|
mTaskOrganizer, mDisplayController, mDisplayImeController,
|
||||||
|
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
|
||||||
|
mIconProvider, mMainExecutor, mRecentTasksOptional);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Context getContext() {
|
public Context getContext() {
|
||||||
return mContext;
|
return mContext;
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import android.annotation.CallSuper;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.IActivityTaskManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.WindowConfiguration;
|
import android.app.WindowConfiguration;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -81,6 +82,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
@@ -244,7 +246,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
|
protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
|
||||||
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
|
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
|
||||||
DisplayImeController displayImeController,
|
DisplayImeController displayImeController,
|
||||||
DisplayInsetsController displayInsetsController, Transitions transitions,
|
DisplayInsetsController displayInsetsController, Transitions transitions,
|
||||||
@@ -879,6 +881,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
WindowContainerTransaction wct, @ExitReason int exitReason) {
|
WindowContainerTransaction wct, @ExitReason int exitReason) {
|
||||||
if (!mMainStage.isActive() || mIsExiting) return;
|
if (!mMainStage.isActive() || mIsExiting) return;
|
||||||
|
|
||||||
|
onSplitScreenExit();
|
||||||
|
|
||||||
mRecentTasks.ifPresent(recentTasks -> {
|
mRecentTasks.ifPresent(recentTasks -> {
|
||||||
// Notify recents if we are exiting in a way that breaks the pair, and disable further
|
// Notify recents if we are exiting in a way that breaks the pair, and disable further
|
||||||
// updates to splits in the recents until we enter split again
|
// updates to splits in the recents until we enter split again
|
||||||
@@ -947,6 +951,47 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overridden by child classes.
|
||||||
|
*/
|
||||||
|
protected void onSplitScreenEnter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overridden by child classes.
|
||||||
|
*/
|
||||||
|
protected void onSplitScreenExit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exits the split screen by finishing one of the tasks.
|
||||||
|
*/
|
||||||
|
protected void exitStage(@SplitPosition int stageToClose) {
|
||||||
|
if (ENABLE_SHELL_TRANSITIONS) {
|
||||||
|
StageTaskListener stageToTop = mSideStagePosition == stageToClose
|
||||||
|
? mMainStage
|
||||||
|
: mSideStage;
|
||||||
|
exitSplitScreen(stageToTop, EXIT_REASON_APP_FINISHED);
|
||||||
|
} else {
|
||||||
|
boolean toEnd = stageToClose == SPLIT_POSITION_BOTTOM_OR_RIGHT;
|
||||||
|
mSplitLayout.flingDividerToDismiss(toEnd, EXIT_REASON_APP_FINISHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grants focus to the main or the side stages.
|
||||||
|
*/
|
||||||
|
protected void grantFocusToStage(@SplitPosition int stageToFocus) {
|
||||||
|
IActivityTaskManager activityTaskManagerService = IActivityTaskManager.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE));
|
||||||
|
try {
|
||||||
|
activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus));
|
||||||
|
} catch (RemoteException | NullPointerException e) {
|
||||||
|
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
|
||||||
|
"%s: Unable to update focus on the chosen stage, %s", TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the split pair in the recent tasks list should be broken.
|
* Returns whether the split pair in the recent tasks list should be broken.
|
||||||
*/
|
*/
|
||||||
@@ -994,6 +1039,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
|
@Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
|
||||||
if (mMainStage.isActive()) return;
|
if (mMainStage.isActive()) return;
|
||||||
|
|
||||||
|
onSplitScreenEnter();
|
||||||
if (taskInfo != null) {
|
if (taskInfo != null) {
|
||||||
setSideStagePosition(startPosition, wct);
|
setSideStagePosition(startPosition, wct);
|
||||||
mSideStage.addTask(taskInfo, wct);
|
mSideStage.addTask(taskInfo, wct);
|
||||||
@@ -1387,6 +1433,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
}
|
}
|
||||||
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
|
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
|
||||||
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status
|
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status
|
||||||
|
onSplitScreenEnter();
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
mSplitLayout.init();
|
mSplitLayout.init();
|
||||||
mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
|
mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* 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.splitscreen.tv;
|
||||||
|
|
||||||
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
import static android.view.View.INVISIBLE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
|
||||||
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||||
|
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
|
||||||
|
import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.WindowManagerGlobal;
|
||||||
|
|
||||||
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.common.SystemWindows;
|
||||||
|
import com.android.wm.shell.common.split.SplitScreenConstants;
|
||||||
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the interaction logic with the {@link TvSplitMenuView}.
|
||||||
|
* A bridge between {@link TvStageCoordinator} and {@link TvSplitMenuView}.
|
||||||
|
*/
|
||||||
|
public class TvSplitMenuController implements TvSplitMenuView.Listener {
|
||||||
|
|
||||||
|
private static final String TAG = TvSplitMenuController.class.getSimpleName();
|
||||||
|
private static final String ACTION_SHOW_MENU = "com.android.wm.shell.splitscreen.SHOW_MENU";
|
||||||
|
private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final StageController mStageController;
|
||||||
|
private final SystemWindows mSystemWindows;
|
||||||
|
private final Handler mMainHandler;
|
||||||
|
|
||||||
|
private final TvSplitMenuView mSplitMenuView;
|
||||||
|
|
||||||
|
private final ActionBroadcastReceiver mActionBroadcastReceiver;
|
||||||
|
|
||||||
|
private final int mTvButtonFadeAnimationDuration;
|
||||||
|
|
||||||
|
public TvSplitMenuController(Context context, StageController stageController,
|
||||||
|
SystemWindows systemWindows, Handler mainHandler) {
|
||||||
|
mContext = context;
|
||||||
|
mMainHandler = mainHandler;
|
||||||
|
mStageController = stageController;
|
||||||
|
mSystemWindows = systemWindows;
|
||||||
|
|
||||||
|
mTvButtonFadeAnimationDuration = context.getResources()
|
||||||
|
.getInteger(R.integer.tv_window_menu_fade_animation_duration);
|
||||||
|
|
||||||
|
mSplitMenuView = (TvSplitMenuView) LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.tv_split_menu_view, null);
|
||||||
|
mSplitMenuView.setListener(this);
|
||||||
|
|
||||||
|
mActionBroadcastReceiver = new ActionBroadcastReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the menu view for the splitscreen to SystemWindows.
|
||||||
|
*/
|
||||||
|
void addSplitMenuViewToSystemWindows() {
|
||||||
|
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
|
||||||
|
mContext.getResources().getDisplayMetrics().widthPixels,
|
||||||
|
mContext.getResources().getDisplayMetrics().heightPixels,
|
||||||
|
TYPE_DOCK_DIVIDER,
|
||||||
|
FLAG_NOT_TOUCHABLE,
|
||||||
|
PixelFormat.TRANSLUCENT);
|
||||||
|
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||||
|
mSplitMenuView.setAlpha(0);
|
||||||
|
mSystemWindows.addView(mSplitMenuView, lp, DEFAULT_DISPLAY, SHELL_ROOT_LAYER_DIVIDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the menu view for the splitscreen from SystemWindows.
|
||||||
|
*/
|
||||||
|
void removeSplitMenuViewFromSystemWindows() {
|
||||||
|
mSystemWindows.removeView(mSplitMenuView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers BroadcastReceiver when split screen mode is entered.
|
||||||
|
*/
|
||||||
|
void registerBroadcastReceiver() {
|
||||||
|
mActionBroadcastReceiver.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters BroadcastReceiver when split screen mode is entered.
|
||||||
|
*/
|
||||||
|
void unregisterBroadcastReceiver() {
|
||||||
|
mActionBroadcastReceiver.unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPress() {
|
||||||
|
setMenuVisibility(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFocusStage(@SplitScreenConstants.SplitPosition int stageToFocus) {
|
||||||
|
setMenuVisibility(false);
|
||||||
|
mStageController.grantFocusToStage(stageToFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCloseStage(@SplitScreenConstants.SplitPosition int stageToClose) {
|
||||||
|
setMenuVisibility(false);
|
||||||
|
mStageController.exitStage(stageToClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwapPress() {
|
||||||
|
mStageController.swapStages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMenuVisibility(boolean visible) {
|
||||||
|
applyMenuVisibility(visible);
|
||||||
|
setMenuFocus(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyMenuVisibility(boolean visible) {
|
||||||
|
float alphaTarget = visible ? 1F : 0F;
|
||||||
|
|
||||||
|
if (mSplitMenuView.getAlpha() == alphaTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSplitMenuView.animate()
|
||||||
|
.alpha(alphaTarget)
|
||||||
|
.setDuration(mTvButtonFadeAnimationDuration)
|
||||||
|
.withStartAction(() -> {
|
||||||
|
if (alphaTarget != 0) {
|
||||||
|
mSplitMenuView.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withEndAction(() -> {
|
||||||
|
if (alphaTarget == 0) {
|
||||||
|
mSplitMenuView.setVisibility(INVISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMenuFocus(boolean focused) {
|
||||||
|
try {
|
||||||
|
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null,
|
||||||
|
mSystemWindows.getFocusGrantToken(mSplitMenuView), focused);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
|
||||||
|
"%s: Unable to update focus, %s", TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StageController {
|
||||||
|
void grantFocusToStage(@SplitScreenConstants.SplitPosition int stageToFocus);
|
||||||
|
void exitStage(@SplitScreenConstants.SplitPosition int stageToClose);
|
||||||
|
void swapStages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ActionBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
final IntentFilter mIntentFilter;
|
||||||
|
{
|
||||||
|
mIntentFilter = new IntentFilter();
|
||||||
|
mIntentFilter.addAction(ACTION_SHOW_MENU);
|
||||||
|
}
|
||||||
|
boolean mRegistered = false;
|
||||||
|
|
||||||
|
void register() {
|
||||||
|
if (mRegistered) return;
|
||||||
|
|
||||||
|
mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
|
||||||
|
mMainHandler);
|
||||||
|
mRegistered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister() {
|
||||||
|
if (!mRegistered) return;
|
||||||
|
|
||||||
|
mContext.unregisterReceiver(this);
|
||||||
|
mRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
final String action = intent.getAction();
|
||||||
|
|
||||||
|
if (ACTION_SHOW_MENU.equals(action)) {
|
||||||
|
setMenuVisibility(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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.splitscreen.tv;
|
||||||
|
|
||||||
|
import static android.view.KeyEvent.ACTION_DOWN;
|
||||||
|
import static android.view.KeyEvent.KEYCODE_BACK;
|
||||||
|
|
||||||
|
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
|
||||||
|
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.common.split.SplitScreenConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A View for the Menu Window.
|
||||||
|
*/
|
||||||
|
public class TvSplitMenuView extends LinearLayout implements View.OnClickListener {
|
||||||
|
|
||||||
|
private Listener mListener;
|
||||||
|
|
||||||
|
public TvSplitMenuView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TvSplitMenuView(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TvSplitMenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
initButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (mListener == null) return;
|
||||||
|
|
||||||
|
final int id = v.getId();
|
||||||
|
if (id == R.id.tv_split_main_menu_focus_button) {
|
||||||
|
mListener.onFocusStage(SPLIT_POSITION_TOP_OR_LEFT);
|
||||||
|
} else if (id == R.id.tv_split_main_menu_close_button) {
|
||||||
|
mListener.onCloseStage(SPLIT_POSITION_TOP_OR_LEFT);
|
||||||
|
} else if (id == R.id.tv_split_side_menu_focus_button) {
|
||||||
|
mListener.onFocusStage(SPLIT_POSITION_BOTTOM_OR_RIGHT);
|
||||||
|
} else if (id == R.id.tv_split_side_menu_close_button) {
|
||||||
|
mListener.onCloseStage(SPLIT_POSITION_BOTTOM_OR_RIGHT);
|
||||||
|
} else if (id == R.id.tv_split_menu_swap_stages) {
|
||||||
|
mListener.onSwapPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
|
if (event.getAction() == ACTION_DOWN) {
|
||||||
|
if (event.getKeyCode() == KEYCODE_BACK) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onBackPress();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.dispatchKeyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initButtons() {
|
||||||
|
findViewById(R.id.tv_split_main_menu_focus_button).setOnClickListener(this);
|
||||||
|
findViewById(R.id.tv_split_main_menu_close_button).setOnClickListener(this);
|
||||||
|
findViewById(R.id.tv_split_side_menu_focus_button).setOnClickListener(this);
|
||||||
|
findViewById(R.id.tv_split_side_menu_close_button).setOnClickListener(this);
|
||||||
|
findViewById(R.id.tv_split_menu_swap_stages).setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setListener(Listener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
/** "Back" button from the remote control */
|
||||||
|
void onBackPress();
|
||||||
|
|
||||||
|
/** Menu Action Buttons */
|
||||||
|
|
||||||
|
void onFocusStage(@SplitScreenConstants.SplitPosition int stageToFocus);
|
||||||
|
|
||||||
|
void onCloseStage(@SplitScreenConstants.SplitPosition int stageToClose);
|
||||||
|
|
||||||
|
void onSwapPress();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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.splitscreen.tv;
|
||||||
|
|
||||||
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import com.android.launcher3.icons.IconProvider;
|
||||||
|
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.common.SystemWindows;
|
||||||
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
import com.android.wm.shell.splitscreen.SplitscreenEventLogger;
|
||||||
|
import com.android.wm.shell.splitscreen.StageCoordinator;
|
||||||
|
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||||
|
import com.android.wm.shell.sysui.ShellController;
|
||||||
|
import com.android.wm.shell.sysui.ShellInit;
|
||||||
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class inherits from {@link SplitScreenController} and provides {@link TvStageCoordinator}
|
||||||
|
* for Split Screen on TV.
|
||||||
|
*/
|
||||||
|
public class TvSplitScreenController extends SplitScreenController {
|
||||||
|
private final ShellTaskOrganizer mTaskOrganizer;
|
||||||
|
private final SyncTransactionQueue mSyncQueue;
|
||||||
|
private final Context mContext;
|
||||||
|
private final ShellExecutor mMainExecutor;
|
||||||
|
private final DisplayController mDisplayController;
|
||||||
|
private final DisplayImeController mDisplayImeController;
|
||||||
|
private final DisplayInsetsController mDisplayInsetsController;
|
||||||
|
private final Transitions mTransitions;
|
||||||
|
private final TransactionPool mTransactionPool;
|
||||||
|
private final IconProvider mIconProvider;
|
||||||
|
private final Optional<RecentTasksController> mRecentTasksOptional;
|
||||||
|
|
||||||
|
private final Handler mMainHandler;
|
||||||
|
private final SystemWindows mSystemWindows;
|
||||||
|
|
||||||
|
public TvSplitScreenController(Context context,
|
||||||
|
ShellInit shellInit,
|
||||||
|
ShellCommandHandler shellCommandHandler,
|
||||||
|
ShellController shellController,
|
||||||
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
|
SyncTransactionQueue syncQueue,
|
||||||
|
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
|
||||||
|
DisplayController displayController,
|
||||||
|
DisplayImeController displayImeController,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
|
DragAndDropController dragAndDropController,
|
||||||
|
Transitions transitions,
|
||||||
|
TransactionPool transactionPool,
|
||||||
|
IconProvider iconProvider,
|
||||||
|
Optional<RecentTasksController> recentTasks,
|
||||||
|
ShellExecutor mainExecutor,
|
||||||
|
Handler mainHandler,
|
||||||
|
SystemWindows systemWindows) {
|
||||||
|
super(context, shellInit, shellCommandHandler, shellController, shellTaskOrganizer,
|
||||||
|
syncQueue, rootTDAOrganizer, displayController, displayImeController,
|
||||||
|
displayInsetsController, dragAndDropController, transitions, transactionPool,
|
||||||
|
iconProvider, recentTasks, mainExecutor);
|
||||||
|
|
||||||
|
mTaskOrganizer = shellTaskOrganizer;
|
||||||
|
mSyncQueue = syncQueue;
|
||||||
|
mContext = context;
|
||||||
|
mMainExecutor = mainExecutor;
|
||||||
|
mDisplayController = displayController;
|
||||||
|
mDisplayImeController = displayImeController;
|
||||||
|
mDisplayInsetsController = displayInsetsController;
|
||||||
|
mTransitions = transitions;
|
||||||
|
mTransactionPool = transactionPool;
|
||||||
|
mIconProvider = iconProvider;
|
||||||
|
mRecentTasksOptional = recentTasks;
|
||||||
|
|
||||||
|
mMainHandler = mainHandler;
|
||||||
|
mSystemWindows = systemWindows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides Tv-specific StageCoordinator.
|
||||||
|
* @return {@link TvStageCoordinator}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected StageCoordinator createStageCoordinator() {
|
||||||
|
return new TvStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
|
||||||
|
mTaskOrganizer, mDisplayController, mDisplayImeController,
|
||||||
|
mDisplayInsetsController, mTransitions, mTransactionPool,
|
||||||
|
new SplitscreenEventLogger(), mIconProvider, mMainExecutor, mMainHandler,
|
||||||
|
mRecentTasksOptional, mSystemWindows);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.splitscreen.tv;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import com.android.launcher3.icons.IconProvider;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
import com.android.wm.shell.common.SystemWindows;
|
||||||
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
|
import com.android.wm.shell.common.split.SplitScreenConstants;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
|
import com.android.wm.shell.splitscreen.SplitscreenEventLogger;
|
||||||
|
import com.android.wm.shell.splitscreen.StageCoordinator;
|
||||||
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands {@link StageCoordinator} functionality with Tv-specific methods.
|
||||||
|
*/
|
||||||
|
public class TvStageCoordinator extends StageCoordinator
|
||||||
|
implements TvSplitMenuController.StageController {
|
||||||
|
|
||||||
|
private final TvSplitMenuController mTvSplitMenuController;
|
||||||
|
|
||||||
|
public TvStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
|
||||||
|
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
|
||||||
|
DisplayImeController displayImeController,
|
||||||
|
DisplayInsetsController displayInsetsController, Transitions transitions,
|
||||||
|
TransactionPool transactionPool, SplitscreenEventLogger logger,
|
||||||
|
IconProvider iconProvider, ShellExecutor mainExecutor,
|
||||||
|
Handler mainHandler,
|
||||||
|
Optional<RecentTasksController> recentTasks,
|
||||||
|
SystemWindows systemWindows) {
|
||||||
|
super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
|
||||||
|
displayInsetsController, transitions, transactionPool, logger, iconProvider,
|
||||||
|
mainExecutor, recentTasks);
|
||||||
|
|
||||||
|
mTvSplitMenuController = new TvSplitMenuController(context, this,
|
||||||
|
systemWindows, mainHandler);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSplitScreenEnter() {
|
||||||
|
mTvSplitMenuController.addSplitMenuViewToSystemWindows();
|
||||||
|
mTvSplitMenuController.registerBroadcastReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSplitScreenExit() {
|
||||||
|
mTvSplitMenuController.unregisterBroadcastReceiver();
|
||||||
|
mTvSplitMenuController.removeSplitMenuViewFromSystemWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void grantFocusToStage(@SplitScreenConstants.SplitPosition int stageToFocus) {
|
||||||
|
super.grantFocusToStage(stageToFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exitStage(@SplitScreenConstants.SplitPosition int stageToClose) {
|
||||||
|
super.exitStage(stageToClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the stages inside the SplitLayout.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void swapStages() {
|
||||||
|
onDoubleTappedDivider();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user