引言
自Android 7开始官方就支持分屏显示,但没有切换分屏的功能,即交换上下屏幕。直到Android 13开始才支持切换分屏,操作方式是:分屏模式下双击中间分割线就会交换上下屏位置。本文的目的就是在Android 11上实现切换分屏的功能。
下图是Android13切换分屏演示
切换分屏原理说明
systemui启动后就会创建属于分屏模式的两个任务栈,一个StackId=3且mode=split-screen-primary表示上半屏任务栈,显示位置为bounds=[0,0][720,606],一个StackId=4且mode=split-screen-secondary表示下半屏任务栈,显示位置为bounds=[0,626][720,1280]。
要交换上下屏显示,只需要修改下两个任务栈(即bounds)的显示位置即可,修改方式通过修改任务栈关联的SurfaceControl的position和bounds。
修改实现
因为Android13和Android14切换分屏操作是双击中间的分割线,因此我们参看他们的也实现同样的功能。
我这里有android14的代码,我们来看看android14的关键部分:
android14双击分屏分割线代码调用路径
DoubleTapListener.onDoubleTap(MotionEvent e)
mSplitLayout.onDoubleTappedDivider()
mSplitLayoutHandler.onDoubleTappedDivider()
switchSplitPosition("double tap")
switchSplitPosition方法在StageCoordinator.java类里
实现分屏交换的就是红框里的方法。
关键地方找到了就好办了,下面是我在android11上的修改,主要的修改类:
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
修改如下:
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index b6c6afd523b3..981bab3263e4 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -25,7 +25,10 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -36,8 +39,10 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Slog;
import android.view.Display;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceControl;
@@ -55,6 +60,8 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
+import android.window.WindowContainerTransaction;
+import android.window.WindowOrganizer;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.logging.MetricsLogger;
@@ -77,6 +84,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
private static final String TAG = "DividerView";
private static final boolean DEBUG = Divider.DEBUG;
+ private GestureDetector mDoubleTapDetector;
+ boolean mToggleSplitScreen;
public interface DividerCallbacks {
void onDraggingStart();
@@ -175,6 +184,16 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private final Handler mHandler = new Handler();
+ private static final String ACTION_TOGGLE_SPLIT_SCREEN = "action_toggle_split_screen";
+ private BroadcastReceiver mToggleSplitScreenReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(ACTION_TOGGLE_SPLIT_SCREEN)){
+ toggleSplitScreen("receive toggle_split_screen broadcast");
+ }
+ }
+ };