Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +5 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.ClipDescription; import android.content.Context; import android.content.res.Configuration; Loading @@ -54,6 +57,7 @@ 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.animation.Interpolators; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; Loading Loading @@ -205,6 +209,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange break; case ACTION_DRAG_ENTERED: pd.dragLayout.show(); pd.dragLayout.update(event); break; case ACTION_DRAG_LOCATION: pd.dragLayout.update(event); Loading Loading @@ -250,10 +255,6 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange // Hide the window if another drag hasn't been started while animating the drop setDropTargetWindowVisibility(pd, View.INVISIBLE); } // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +7 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,13 @@ public class DragAndDropPolicy { return mSession.runningTaskInfo; } /** * Returns the number of targets. */ int getNumTargets() { return mTargets.size(); } /** * Returns the target's regions based on the current state of the device and display. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +101 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.draganddrop; import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; Loading @@ -24,6 +25,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.StatusBarManager; Loading @@ -44,6 +46,7 @@ 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.animation.Interpolators; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading Loading @@ -135,6 +138,12 @@ public class DragLayout extends LinearLayout { } } private void updateContainerMarginsForSingleTask() { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin); mDropZoneView2.setContainerMargin(0, 0, 0, 0); } private void updateContainerMargins(int orientation) { final float halfMargin = mDisplayMargin / 2f; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { Loading Loading @@ -165,11 +174,20 @@ public class DragLayout extends LinearLayout { if (!alreadyInSplit) { ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask(); if (taskInfo1 != null) { final int activityType = taskInfo1.getActivityType(); if (activityType == ACTIVITY_TYPE_STANDARD) { Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo); int bgColor1 = getResizingBackgroundColor(taskInfo1); mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); updateDropZoneSizes(null, null); // passing null splits the views evenly } else { // We use the first drop zone to show the fullscreen highlight, and don't need // to set additional info mDropZoneView1.setForceIgnoreBottomMargin(true); updateDropZoneSizesForSingleTask(); updateContainerMarginsForSingleTask(); } } } else { // We're already in split so get taskInfo from the controller to populate icon / color. Loading @@ -195,6 +213,21 @@ public class DragLayout extends LinearLayout { } } private void updateDropZoneSizesForSingleTask() { final LinearLayout.LayoutParams dropZoneView1 = (LayoutParams) mDropZoneView1.getLayoutParams(); final LinearLayout.LayoutParams dropZoneView2 = (LayoutParams) mDropZoneView2.getLayoutParams(); dropZoneView1.width = MATCH_PARENT; dropZoneView1.height = MATCH_PARENT; dropZoneView2.width = 0; dropZoneView2.height = 0; dropZoneView1.weight = 1; dropZoneView2.weight = 0; mDropZoneView1.setLayoutParams(dropZoneView1); mDropZoneView2.setLayoutParams(dropZoneView2); } /** * Sets the size of the two drop zones based on the provided bounds. The divider sits between * the views and its size is included in the calculations. Loading Loading @@ -265,9 +298,12 @@ public class DragLayout extends LinearLayout { // Animating to no target animateSplitContainers(false, null /* animCompleteCallback */); } else if (mCurrentTarget == null) { // Animating to first target if (mPolicy.getNumTargets() == 1) { animateFullscreenContainer(true); } else { animateSplitContainers(true, null /* animCompleteCallback */); animateHighlight(target); } } else { // Switching between targets mDropZoneView1.animateSwitch(); Loading @@ -283,6 +319,10 @@ public class DragLayout extends LinearLayout { public void hide(DragEvent event, Runnable hideCompleteCallback) { mIsShowing = false; animateSplitContainers(false, hideCompleteCallback); // Reset the state if we previously force-ignore the bottom margin mDropZoneView1.setForceIgnoreBottomMargin(false); mDropZoneView2.setForceIgnoreBottomMargin(false); updateContainerMargins(getResources().getConfiguration().orientation); mCurrentTarget = null; } Loading @@ -297,11 +337,63 @@ public class DragLayout extends LinearLayout { // Process the drop mPolicy.handleDrop(mCurrentTarget, event.getClipData()); // TODO(b/169894807): Coordinate with dragSurface // Start animating the drop UI out with the drag surface hide(event, dropCompleteCallback); hideDragSurface(dragSurface); return handledDrop; } private void hideDragSurface(SurfaceControl dragSurface) { final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final ValueAnimator dragSurfaceAnimator = ValueAnimator.ofFloat(0f, 1f); // Currently the splash icon animation runs with the default ValueAnimator duration of // 300ms dragSurfaceAnimator.setDuration(300); dragSurfaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); dragSurfaceAnimator.addUpdateListener(animation -> { float t = animation.getAnimatedFraction(); float alpha = 1f - t; // TODO: Scale the drag surface as well once we make all the source surfaces // consistent tx.setAlpha(dragSurface, alpha); tx.apply(); }); dragSurfaceAnimator.addListener(new AnimatorListenerAdapter() { private boolean mCanceled = false; @Override public void onAnimationCancel(Animator animation) { cleanUpSurface(); mCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (mCanceled) { // Already handled above return; } cleanUpSurface(); } private void cleanUpSurface() { // Clean up the drag surface tx.remove(dragSurface); tx.apply(); } }); dragSurfaceAnimator.start(); } private void animateFullscreenContainer(boolean visible) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE); // We're only using the first drop zone if there is one fullscreen target mDropZoneView1.setShowingMargin(visible); mDropZoneView1.setShowingHighlight(visible); } private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java +11 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ public class DropZoneView extends FrameLayout { private final float[] mContainerMargin = new float[4]; private float mCornerRadius; private float mBottomInset; private boolean mIgnoreBottomMargin; private int mMarginColor; // i.e. color used for negative space like the container insets private boolean mShowingHighlight; Loading Loading @@ -141,6 +142,14 @@ public class DropZoneView extends FrameLayout { } } /** Ignores the bottom margin provided by the insets. */ public void setForceIgnoreBottomMargin(boolean ignoreBottomMargin) { mIgnoreBottomMargin = ignoreBottomMargin; if (mMarginPercent > 0) { mMarginView.invalidate(); } } /** Sets the bottom inset so the drop zones are above bottom navigation. */ public void setBottomInset(float bottom) { mBottomInset = bottom; Loading Loading @@ -257,7 +266,8 @@ public class DropZoneView extends FrameLayout { mPath.addRoundRect(mContainerMargin[0] * mMarginPercent, mContainerMargin[1] * mMarginPercent, getWidth() - (mContainerMargin[2] * mMarginPercent), getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset, getHeight() - (mContainerMargin[3] * mMarginPercent) - (mIgnoreBottomMargin ? 0 : mBottomInset), mCornerRadius * mMarginPercent, mCornerRadius * mMarginPercent, Path.Direction.CW); Loading packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2407,4 +2407,7 @@ <string name="add_user_supervised" translatable="false">@*android:string/supervised_user_creation_label</string> <!-- Manage users - For system user management [CHAR LIMIT=40] --> <string name="manage_users">Manage users</string> <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] --> <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string> </resources> Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +5 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.ClipDescription; import android.content.Context; import android.content.res.Configuration; Loading @@ -54,6 +57,7 @@ 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.animation.Interpolators; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; Loading Loading @@ -205,6 +209,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange break; case ACTION_DRAG_ENTERED: pd.dragLayout.show(); pd.dragLayout.update(event); break; case ACTION_DRAG_LOCATION: pd.dragLayout.update(event); Loading Loading @@ -250,10 +255,6 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange // Hide the window if another drag hasn't been started while animating the drop setDropTargetWindowVisibility(pd, View.INVISIBLE); } // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +7 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,13 @@ public class DragAndDropPolicy { return mSession.runningTaskInfo; } /** * Returns the number of targets. */ int getNumTargets() { return mTargets.size(); } /** * Returns the target's regions based on the current state of the device and display. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +101 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.draganddrop; import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; Loading @@ -24,6 +25,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.StatusBarManager; Loading @@ -44,6 +46,7 @@ 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.animation.Interpolators; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading Loading @@ -135,6 +138,12 @@ public class DragLayout extends LinearLayout { } } private void updateContainerMarginsForSingleTask() { mDropZoneView1.setContainerMargin( mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin); mDropZoneView2.setContainerMargin(0, 0, 0, 0); } private void updateContainerMargins(int orientation) { final float halfMargin = mDisplayMargin / 2f; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { Loading Loading @@ -165,11 +174,20 @@ public class DragLayout extends LinearLayout { if (!alreadyInSplit) { ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask(); if (taskInfo1 != null) { final int activityType = taskInfo1.getActivityType(); if (activityType == ACTIVITY_TYPE_STANDARD) { Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo); int bgColor1 = getResizingBackgroundColor(taskInfo1); mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); updateDropZoneSizes(null, null); // passing null splits the views evenly } else { // We use the first drop zone to show the fullscreen highlight, and don't need // to set additional info mDropZoneView1.setForceIgnoreBottomMargin(true); updateDropZoneSizesForSingleTask(); updateContainerMarginsForSingleTask(); } } } else { // We're already in split so get taskInfo from the controller to populate icon / color. Loading @@ -195,6 +213,21 @@ public class DragLayout extends LinearLayout { } } private void updateDropZoneSizesForSingleTask() { final LinearLayout.LayoutParams dropZoneView1 = (LayoutParams) mDropZoneView1.getLayoutParams(); final LinearLayout.LayoutParams dropZoneView2 = (LayoutParams) mDropZoneView2.getLayoutParams(); dropZoneView1.width = MATCH_PARENT; dropZoneView1.height = MATCH_PARENT; dropZoneView2.width = 0; dropZoneView2.height = 0; dropZoneView1.weight = 1; dropZoneView2.weight = 0; mDropZoneView1.setLayoutParams(dropZoneView1); mDropZoneView2.setLayoutParams(dropZoneView2); } /** * Sets the size of the two drop zones based on the provided bounds. The divider sits between * the views and its size is included in the calculations. Loading Loading @@ -265,9 +298,12 @@ public class DragLayout extends LinearLayout { // Animating to no target animateSplitContainers(false, null /* animCompleteCallback */); } else if (mCurrentTarget == null) { // Animating to first target if (mPolicy.getNumTargets() == 1) { animateFullscreenContainer(true); } else { animateSplitContainers(true, null /* animCompleteCallback */); animateHighlight(target); } } else { // Switching between targets mDropZoneView1.animateSwitch(); Loading @@ -283,6 +319,10 @@ public class DragLayout extends LinearLayout { public void hide(DragEvent event, Runnable hideCompleteCallback) { mIsShowing = false; animateSplitContainers(false, hideCompleteCallback); // Reset the state if we previously force-ignore the bottom margin mDropZoneView1.setForceIgnoreBottomMargin(false); mDropZoneView2.setForceIgnoreBottomMargin(false); updateContainerMargins(getResources().getConfiguration().orientation); mCurrentTarget = null; } Loading @@ -297,11 +337,63 @@ public class DragLayout extends LinearLayout { // Process the drop mPolicy.handleDrop(mCurrentTarget, event.getClipData()); // TODO(b/169894807): Coordinate with dragSurface // Start animating the drop UI out with the drag surface hide(event, dropCompleteCallback); hideDragSurface(dragSurface); return handledDrop; } private void hideDragSurface(SurfaceControl dragSurface) { final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final ValueAnimator dragSurfaceAnimator = ValueAnimator.ofFloat(0f, 1f); // Currently the splash icon animation runs with the default ValueAnimator duration of // 300ms dragSurfaceAnimator.setDuration(300); dragSurfaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); dragSurfaceAnimator.addUpdateListener(animation -> { float t = animation.getAnimatedFraction(); float alpha = 1f - t; // TODO: Scale the drag surface as well once we make all the source surfaces // consistent tx.setAlpha(dragSurface, alpha); tx.apply(); }); dragSurfaceAnimator.addListener(new AnimatorListenerAdapter() { private boolean mCanceled = false; @Override public void onAnimationCancel(Animator animation) { cleanUpSurface(); mCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (mCanceled) { // Already handled above return; } cleanUpSurface(); } private void cleanUpSurface() { // Clean up the drag surface tx.remove(dragSurface); tx.apply(); } }); dragSurfaceAnimator.start(); } private void animateFullscreenContainer(boolean visible) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE); // We're only using the first drop zone if there is one fullscreen target mDropZoneView1.setShowingMargin(visible); mDropZoneView1.setShowingHighlight(visible); } private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) { mStatusBarManager.disable(visible ? HIDE_STATUS_BAR_FLAGS Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java +11 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ public class DropZoneView extends FrameLayout { private final float[] mContainerMargin = new float[4]; private float mCornerRadius; private float mBottomInset; private boolean mIgnoreBottomMargin; private int mMarginColor; // i.e. color used for negative space like the container insets private boolean mShowingHighlight; Loading Loading @@ -141,6 +142,14 @@ public class DropZoneView extends FrameLayout { } } /** Ignores the bottom margin provided by the insets. */ public void setForceIgnoreBottomMargin(boolean ignoreBottomMargin) { mIgnoreBottomMargin = ignoreBottomMargin; if (mMarginPercent > 0) { mMarginView.invalidate(); } } /** Sets the bottom inset so the drop zones are above bottom navigation. */ public void setBottomInset(float bottom) { mBottomInset = bottom; Loading Loading @@ -257,7 +266,8 @@ public class DropZoneView extends FrameLayout { mPath.addRoundRect(mContainerMargin[0] * mMarginPercent, mContainerMargin[1] * mMarginPercent, getWidth() - (mContainerMargin[2] * mMarginPercent), getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset, getHeight() - (mContainerMargin[3] * mMarginPercent) - (mIgnoreBottomMargin ? 0 : mBottomInset), mCornerRadius * mMarginPercent, mCornerRadius * mMarginPercent, Path.Direction.CW); Loading
packages/SystemUI/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -2407,4 +2407,7 @@ <string name="add_user_supervised" translatable="false">@*android:string/supervised_user_creation_label</string> <!-- Manage users - For system user management [CHAR LIMIT=40] --> <string name="manage_users">Manage users</string> <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] --> <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string> </resources>