Loading libs/WindowManager/Shell/res/color/taskbar_background.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2021 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. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@android:color/system_neutral1_500" android:lStar="35" /> </selector> No newline at end of file libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +11 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.common.annotations.ShellSplashscreenThread; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.displayareahelper.DisplayAreaHelperController; import com.android.wm.shell.draganddrop.DragAndDrop; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener; Loading Loading @@ -156,8 +157,16 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static DragAndDropController provideDragAndDropController(Context context, DisplayController displayController, UiEventLogger uiEventLogger) { return new DragAndDropController(context, displayController, uiEventLogger); DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) { return new DragAndDropController(context, displayController, uiEventLogger, iconProvider, mainExecutor); } @WMSingleton @Provides static DragAndDrop provideDragAndDrop(DragAndDropController dragAndDropController) { return dragAndDropController.asDragAndDrop(); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java 0 → 100644 +34 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.draganddrop; import android.content.res.Configuration; import com.android.wm.shell.common.annotations.ExternalThread; /** * Interface for telling DragAndDrop stuff. */ @ExternalThread public interface DragAndDrop { /** Called when the theme changes. */ void onThemeChanged(); /** Called when the configuration changes. */ void onConfigChanged(Configuration newConfig); } libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +43 −3 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DragEvent; import android.view.LayoutInflater; import android.view.SurfaceControl; Loading @@ -53,8 +52,10 @@ import android.widget.FrameLayout; import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading @@ -71,16 +72,26 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private final Context mContext; private final DisplayController mDisplayController; private final DragAndDropEventLogger mLogger; private final IconProvider mIconProvider; private SplitScreenController mSplitScreen; private ShellExecutor mMainExecutor; private DragAndDropImpl mImpl; private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>(); private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); public DragAndDropController(Context context, DisplayController displayController, UiEventLogger uiEventLogger) { UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) { mContext = context; mDisplayController = displayController; mLogger = new DragAndDropEventLogger(uiEventLogger); mIconProvider = iconProvider; mMainExecutor = mainExecutor; mImpl = new DragAndDropImpl(); } public DragAndDrop asDragAndDrop() { return mImpl; } public void initialize(Optional<SplitScreenController> splitscreen) { Loading Loading @@ -117,7 +128,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange R.layout.global_drop_target, null); rootView.setOnDragListener(this); rootView.setVisibility(View.INVISIBLE); DragLayout dragLayout = new DragLayout(context, mSplitScreen); DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider); rootView.addView(dragLayout, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); try { Loading Loading @@ -267,6 +278,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return mimeTypes; } private void onThemeChange() { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onThemeChange(); } } private void onConfigChanged(Configuration newConfig) { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig); } } private static class PerDisplay { final int displayId; final Context context; Loading @@ -287,4 +310,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange dragLayout = dl; } } private class DragAndDropImpl implements DragAndDrop { @Override public void onThemeChanged() { mMainExecutor.execute(() -> { DragAndDropController.this.onThemeChange(); }); } @Override public void onConfigChanged(Configuration newConfig) { mMainExecutor.execute(() -> { DragAndDropController.this.onConfigChanged(newConfig); }); } } } libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +171 −54 Original line number Diff line number Diff line Loading @@ -16,78 +16,138 @@ package com.android.wm.shell.draganddrop; import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN; import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN; import static com.android.wm.shell.animation.Interpolators.LINEAR; import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN; import static android.app.StatusBarManager.DISABLE_NONE; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.StatusBarManager; import android.content.ClipData; import android.content.Context; import android.graphics.Canvas; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.view.DragEvent; import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.WindowInsets.Type; import androidx.annotation.NonNull; import android.widget.LinearLayout; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.ArrayList; import java.util.List; /** * Coordinates the visible drop targets for the current drag. */ public class DragLayout extends View { public class DragLayout extends LinearLayout { // While dragging the status bar is hidden. private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_ALERTS | StatusBarManager.DISABLE_CLOCK | StatusBarManager.DISABLE_SYSTEM_INFO; private final DragAndDropPolicy mPolicy; private final SplitScreenController mSplitScreenController; private final IconProvider mIconProvider; private final StatusBarManager mStatusBarManager; private DragAndDropPolicy.Target mCurrentTarget = null; private DropOutlineDrawable mDropOutline; private DropZoneView mDropZoneView1; private DropZoneView mDropZoneView2; private int mDisplayMargin; private Insets mInsets = Insets.NONE; private boolean mIsShowing; private boolean mHasDropped; public DragLayout(Context context, SplitScreenController splitscreen) { @SuppressLint("WrongConstant") public DragLayout(Context context, SplitScreenController splitScreenController, IconProvider iconProvider) { super(context); mPolicy = new DragAndDropPolicy(context, splitscreen); mSplitScreenController = splitScreenController; mIconProvider = iconProvider; mPolicy = new DragAndDropPolicy(context, splitScreenController); mStatusBarManager = context.getSystemService(StatusBarManager.class); mDisplayMargin = context.getResources().getDimensionPixelSize( R.dimen.drop_layout_display_margin); mDropOutline = new DropOutlineDrawable(context); setBackground(mDropOutline); setWillNotDraw(false); mDropZoneView1 = new DropZoneView(context); mDropZoneView2 = new DropZoneView(context); addView(mDropZoneView1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); addView(mDropZoneView2, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1; ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1; updateContainerMargins(); } @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout()); recomputeDropTargets(); final int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mDropZoneView1.setBottomInset(mInsets.bottom); mDropZoneView2.setBottomInset(mInsets.bottom); } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { mDropZoneView1.setBottomInset(0); mDropZoneView2.setBottomInset(mInsets.bottom); } return super.onApplyWindowInsets(insets); } @Override protected boolean verifyDrawable(@NonNull Drawable who) { return who == mDropOutline || super.verifyDrawable(who); public void onThemeChange() { mDropZoneView1.onThemeChange(); mDropZoneView2.onThemeChange(); } @Override protected void onDraw(Canvas canvas) { if (mCurrentTarget != null) { mDropOutline.draw(canvas); public void onConfigChanged(Configuration newConfig) { final int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE && getOrientation() != HORIZONTAL) { setOrientation(LinearLayout.HORIZONTAL); updateContainerMargins(); } else if (orientation == Configuration.ORIENTATION_PORTRAIT && getOrientation() != VERTICAL) { setOrientation(LinearLayout.VERTICAL); updateContainerMargins(); } } private void updateContainerMargins() { final int orientation = getResources().getConfiguration().orientation; final float halfMargin = mDisplayMargin / 2f; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, halfMargin, mDisplayMargin); mDropZoneView2.setContainerMargin( halfMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin); } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, mDisplayMargin, halfMargin); mDropZoneView2.setContainerMargin( mDisplayMargin, halfMargin, mDisplayMargin, mDisplayMargin); } } Loading @@ -104,6 +164,43 @@ public class DragLayout extends View { mPolicy.start(displayLayout, initialData, loggerSessionId); mHasDropped = false; mCurrentTarget = null; List<ActivityManager.RunningTaskInfo> tasks = null; // Figure out the splashscreen info for the existing task(s). try { tasks = ActivityTaskManager.getService().getTasks(2, false /* filterOnlyVisibleRecents */, false /* keepIntentExtra */); } catch (RemoteException e) { // don't show an icon / will just use the defaults } if (tasks != null && !tasks.isEmpty()) { ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0); Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo); int bgColor1 = getResizingBackgroundColor(taskInfo1); boolean alreadyInSplit = mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible(); if (alreadyInSplit && tasks.size() > 1) { ActivityManager.RunningTaskInfo taskInfo2 = tasks.get(1); Drawable icon2 = mIconProvider.getIcon(taskInfo2.topActivityInfo); int bgColor2 = getResizingBackgroundColor(taskInfo2); // figure out which task is on which side int splitPosition1 = mSplitScreenController.getSplitPosition(taskInfo1.taskId); boolean isTask1TopOrLeft = splitPosition1 == SPLIT_POSITION_TOP_OR_LEFT; if (isTask1TopOrLeft) { mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor2, icon2); } else { mDropZoneView2.setAppInfo(bgColor1, icon1); mDropZoneView1.setAppInfo(bgColor2, icon2); } } else { mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); } } } public void show() { Loading Loading @@ -139,20 +236,14 @@ public class DragLayout extends View { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target); if (target == null) { // Animating to no target mDropOutline.startVisibilityAnimation(false, LINEAR); Rect finalBounds = new Rect(mCurrentTarget.drawRegion); finalBounds.inset(mDisplayMargin, mDisplayMargin); mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN); animateSplitContainers(false, null /* animCompleteCallback */); } else if (mCurrentTarget == null) { // Animating to first target mDropOutline.startVisibilityAnimation(true, LINEAR); Rect initialBounds = new Rect(target.drawRegion); initialBounds.inset(mDisplayMargin, mDisplayMargin); mDropOutline.setRegionBounds(initialBounds); mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN); animateSplitContainers(true, null /* animCompleteCallback */); animateHighlight(target); } else { // Bounds change mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN); // Switching between targets animateHighlight(target); } mCurrentTarget = target; } Loading @@ -163,26 +254,7 @@ public class DragLayout extends View { */ public void hide(DragEvent event, Runnable hideCompleteCallback) { mIsShowing = false; ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR); ObjectAnimator boundsAnimator = null; if (mCurrentTarget != null) { Rect finalBounds = new Rect(mCurrentTarget.drawRegion); finalBounds.inset(mDisplayMargin, mDisplayMargin); boundsAnimator = mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN); } if (hideCompleteCallback != null) { ObjectAnimator lastAnim = boundsAnimator != null ? boundsAnimator : alphaAnimator; lastAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { hideCompleteCallback.run(); } }); } animateSplitContainers(false, hideCompleteCallback); mCurrentTarget = null; } Loading @@ -201,4 +273,49 @@ public class DragLayout extends View { hide(event, dropCompleteCallback); return handledDrop; } private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE); mDropZoneView1.setShowingMargin(visible); mDropZoneView2.setShowingMargin(visible); ObjectAnimator animator = mDropZoneView1.getAnimator(); if (animCompleteCallback != null) { if (animator != null) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animCompleteCallback.run(); } }); } else { // If there's no animator the animation is done so run immediately animCompleteCallback.run(); } } } private void animateHighlight(DragAndDropPolicy.Target target) { if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) { mDropZoneView1.setShowingHighlight(true); mDropZoneView1.setShowingSplash(false); mDropZoneView2.setShowingHighlight(false); mDropZoneView2.setShowingSplash(true); } else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) { mDropZoneView1.setShowingHighlight(false); mDropZoneView1.setShowingSplash(true); mDropZoneView2.setShowingHighlight(true); mDropZoneView2.setShowingSplash(false); } } private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb(); } } Loading
libs/WindowManager/Shell/res/color/taskbar_background.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2021 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. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@android:color/system_neutral1_500" android:lStar="35" /> </selector> No newline at end of file
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +11 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.common.annotations.ShellSplashscreenThread; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.displayareahelper.DisplayAreaHelperController; import com.android.wm.shell.draganddrop.DragAndDrop; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener; Loading Loading @@ -156,8 +157,16 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static DragAndDropController provideDragAndDropController(Context context, DisplayController displayController, UiEventLogger uiEventLogger) { return new DragAndDropController(context, displayController, uiEventLogger); DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) { return new DragAndDropController(context, displayController, uiEventLogger, iconProvider, mainExecutor); } @WMSingleton @Provides static DragAndDrop provideDragAndDrop(DragAndDropController dragAndDropController) { return dragAndDropController.asDragAndDrop(); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java 0 → 100644 +34 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.draganddrop; import android.content.res.Configuration; import com.android.wm.shell.common.annotations.ExternalThread; /** * Interface for telling DragAndDrop stuff. */ @ExternalThread public interface DragAndDrop { /** Called when the theme changes. */ void onThemeChanged(); /** Called when the configuration changes. */ void onConfigChanged(Configuration newConfig); }
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +43 −3 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DragEvent; import android.view.LayoutInflater; import android.view.SurfaceControl; Loading @@ -53,8 +52,10 @@ import android.widget.FrameLayout; import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading @@ -71,16 +72,26 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private final Context mContext; private final DisplayController mDisplayController; private final DragAndDropEventLogger mLogger; private final IconProvider mIconProvider; private SplitScreenController mSplitScreen; private ShellExecutor mMainExecutor; private DragAndDropImpl mImpl; private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>(); private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); public DragAndDropController(Context context, DisplayController displayController, UiEventLogger uiEventLogger) { UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) { mContext = context; mDisplayController = displayController; mLogger = new DragAndDropEventLogger(uiEventLogger); mIconProvider = iconProvider; mMainExecutor = mainExecutor; mImpl = new DragAndDropImpl(); } public DragAndDrop asDragAndDrop() { return mImpl; } public void initialize(Optional<SplitScreenController> splitscreen) { Loading Loading @@ -117,7 +128,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange R.layout.global_drop_target, null); rootView.setOnDragListener(this); rootView.setVisibility(View.INVISIBLE); DragLayout dragLayout = new DragLayout(context, mSplitScreen); DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider); rootView.addView(dragLayout, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); try { Loading Loading @@ -267,6 +278,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return mimeTypes; } private void onThemeChange() { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onThemeChange(); } } private void onConfigChanged(Configuration newConfig) { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig); } } private static class PerDisplay { final int displayId; final Context context; Loading @@ -287,4 +310,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange dragLayout = dl; } } private class DragAndDropImpl implements DragAndDrop { @Override public void onThemeChanged() { mMainExecutor.execute(() -> { DragAndDropController.this.onThemeChange(); }); } @Override public void onConfigChanged(Configuration newConfig) { mMainExecutor.execute(() -> { DragAndDropController.this.onConfigChanged(newConfig); }); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +171 −54 Original line number Diff line number Diff line Loading @@ -16,78 +16,138 @@ package com.android.wm.shell.draganddrop; import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN; import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN; import static com.android.wm.shell.animation.Interpolators.LINEAR; import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN; import static android.app.StatusBarManager.DISABLE_NONE; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.StatusBarManager; import android.content.ClipData; import android.content.Context; import android.graphics.Canvas; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.view.DragEvent; import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.WindowInsets.Type; import androidx.annotation.NonNull; import android.widget.LinearLayout; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.ArrayList; import java.util.List; /** * Coordinates the visible drop targets for the current drag. */ public class DragLayout extends View { public class DragLayout extends LinearLayout { // While dragging the status bar is hidden. private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_ALERTS | StatusBarManager.DISABLE_CLOCK | StatusBarManager.DISABLE_SYSTEM_INFO; private final DragAndDropPolicy mPolicy; private final SplitScreenController mSplitScreenController; private final IconProvider mIconProvider; private final StatusBarManager mStatusBarManager; private DragAndDropPolicy.Target mCurrentTarget = null; private DropOutlineDrawable mDropOutline; private DropZoneView mDropZoneView1; private DropZoneView mDropZoneView2; private int mDisplayMargin; private Insets mInsets = Insets.NONE; private boolean mIsShowing; private boolean mHasDropped; public DragLayout(Context context, SplitScreenController splitscreen) { @SuppressLint("WrongConstant") public DragLayout(Context context, SplitScreenController splitScreenController, IconProvider iconProvider) { super(context); mPolicy = new DragAndDropPolicy(context, splitscreen); mSplitScreenController = splitScreenController; mIconProvider = iconProvider; mPolicy = new DragAndDropPolicy(context, splitScreenController); mStatusBarManager = context.getSystemService(StatusBarManager.class); mDisplayMargin = context.getResources().getDimensionPixelSize( R.dimen.drop_layout_display_margin); mDropOutline = new DropOutlineDrawable(context); setBackground(mDropOutline); setWillNotDraw(false); mDropZoneView1 = new DropZoneView(context); mDropZoneView2 = new DropZoneView(context); addView(mDropZoneView1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); addView(mDropZoneView2, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1; ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1; updateContainerMargins(); } @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout()); recomputeDropTargets(); final int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mDropZoneView1.setBottomInset(mInsets.bottom); mDropZoneView2.setBottomInset(mInsets.bottom); } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { mDropZoneView1.setBottomInset(0); mDropZoneView2.setBottomInset(mInsets.bottom); } return super.onApplyWindowInsets(insets); } @Override protected boolean verifyDrawable(@NonNull Drawable who) { return who == mDropOutline || super.verifyDrawable(who); public void onThemeChange() { mDropZoneView1.onThemeChange(); mDropZoneView2.onThemeChange(); } @Override protected void onDraw(Canvas canvas) { if (mCurrentTarget != null) { mDropOutline.draw(canvas); public void onConfigChanged(Configuration newConfig) { final int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE && getOrientation() != HORIZONTAL) { setOrientation(LinearLayout.HORIZONTAL); updateContainerMargins(); } else if (orientation == Configuration.ORIENTATION_PORTRAIT && getOrientation() != VERTICAL) { setOrientation(LinearLayout.VERTICAL); updateContainerMargins(); } } private void updateContainerMargins() { final int orientation = getResources().getConfiguration().orientation; final float halfMargin = mDisplayMargin / 2f; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, halfMargin, mDisplayMargin); mDropZoneView2.setContainerMargin( halfMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin); } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, mDisplayMargin, halfMargin); mDropZoneView2.setContainerMargin( mDisplayMargin, halfMargin, mDisplayMargin, mDisplayMargin); } } Loading @@ -104,6 +164,43 @@ public class DragLayout extends View { mPolicy.start(displayLayout, initialData, loggerSessionId); mHasDropped = false; mCurrentTarget = null; List<ActivityManager.RunningTaskInfo> tasks = null; // Figure out the splashscreen info for the existing task(s). try { tasks = ActivityTaskManager.getService().getTasks(2, false /* filterOnlyVisibleRecents */, false /* keepIntentExtra */); } catch (RemoteException e) { // don't show an icon / will just use the defaults } if (tasks != null && !tasks.isEmpty()) { ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0); Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo); int bgColor1 = getResizingBackgroundColor(taskInfo1); boolean alreadyInSplit = mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible(); if (alreadyInSplit && tasks.size() > 1) { ActivityManager.RunningTaskInfo taskInfo2 = tasks.get(1); Drawable icon2 = mIconProvider.getIcon(taskInfo2.topActivityInfo); int bgColor2 = getResizingBackgroundColor(taskInfo2); // figure out which task is on which side int splitPosition1 = mSplitScreenController.getSplitPosition(taskInfo1.taskId); boolean isTask1TopOrLeft = splitPosition1 == SPLIT_POSITION_TOP_OR_LEFT; if (isTask1TopOrLeft) { mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor2, icon2); } else { mDropZoneView2.setAppInfo(bgColor1, icon1); mDropZoneView1.setAppInfo(bgColor2, icon2); } } else { mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); } } } public void show() { Loading Loading @@ -139,20 +236,14 @@ public class DragLayout extends View { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target); if (target == null) { // Animating to no target mDropOutline.startVisibilityAnimation(false, LINEAR); Rect finalBounds = new Rect(mCurrentTarget.drawRegion); finalBounds.inset(mDisplayMargin, mDisplayMargin); mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN); animateSplitContainers(false, null /* animCompleteCallback */); } else if (mCurrentTarget == null) { // Animating to first target mDropOutline.startVisibilityAnimation(true, LINEAR); Rect initialBounds = new Rect(target.drawRegion); initialBounds.inset(mDisplayMargin, mDisplayMargin); mDropOutline.setRegionBounds(initialBounds); mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN); animateSplitContainers(true, null /* animCompleteCallback */); animateHighlight(target); } else { // Bounds change mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN); // Switching between targets animateHighlight(target); } mCurrentTarget = target; } Loading @@ -163,26 +254,7 @@ public class DragLayout extends View { */ public void hide(DragEvent event, Runnable hideCompleteCallback) { mIsShowing = false; ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR); ObjectAnimator boundsAnimator = null; if (mCurrentTarget != null) { Rect finalBounds = new Rect(mCurrentTarget.drawRegion); finalBounds.inset(mDisplayMargin, mDisplayMargin); boundsAnimator = mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN); } if (hideCompleteCallback != null) { ObjectAnimator lastAnim = boundsAnimator != null ? boundsAnimator : alphaAnimator; lastAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { hideCompleteCallback.run(); } }); } animateSplitContainers(false, hideCompleteCallback); mCurrentTarget = null; } Loading @@ -201,4 +273,49 @@ public class DragLayout extends View { hide(event, dropCompleteCallback); return handledDrop; } private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE); mDropZoneView1.setShowingMargin(visible); mDropZoneView2.setShowingMargin(visible); ObjectAnimator animator = mDropZoneView1.getAnimator(); if (animCompleteCallback != null) { if (animator != null) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animCompleteCallback.run(); } }); } else { // If there's no animator the animation is done so run immediately animCompleteCallback.run(); } } } private void animateHighlight(DragAndDropPolicy.Target target) { if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) { mDropZoneView1.setShowingHighlight(true); mDropZoneView1.setShowingSplash(false); mDropZoneView2.setShowingHighlight(false); mDropZoneView2.setShowingSplash(true); } else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) { mDropZoneView1.setShowingHighlight(false); mDropZoneView1.setShowingSplash(true); mDropZoneView2.setShowingHighlight(true); mDropZoneView2.setShowingSplash(false); } } private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb(); } }