Couple fixes for drag and drop
- Add simple fade of the drag surface when dropping and when canceling a drag from the shade (since the shade has closed, the default animation of animating to the start position is wrong) - Add case for dragging over home/recents, show the highlighted drop zone as fullscreen since there is nothing to split with - Fix issue with drag listener not being removed after a notification drag - For now, add a toast when attempting to drag a notification that does not have a valid intent - Also don't wait for DRAG_START to start collapsing the shade if the call to startDrag() returns true Bug: 217972792 Bug: 218791595 Bug: 219757067 Test: atest WMShellUnitTests Test: atest SystemUITests Change-Id: Ic53de0d8a999d4ae39dc207bfc2927466ad2ba7c
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -165,11 +174,20 @@ public class DragLayout extends LinearLayout {
|
||||
if (!alreadyInSplit) {
|
||||
ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
|
||||
if (taskInfo1 != null) {
|
||||
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
|
||||
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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
animateSplitContainers(true, null /* animCompleteCallback */);
|
||||
animateHighlight(target);
|
||||
if (mPolicy.getNumTargets() == 1) {
|
||||
animateFullscreenContainer(true);
|
||||
} else {
|
||||
animateSplitContainers(true, null /* animCompleteCallback */);
|
||||
animateHighlight(target);
|
||||
}
|
||||
} else {
|
||||
// Switching between targets
|
||||
mDropZoneView1.animateSwitch();
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
@@ -33,13 +38,15 @@ import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
@@ -55,12 +62,15 @@ public class ExpandableNotificationRowDragController {
|
||||
|
||||
private final Context mContext;
|
||||
private final HeadsUpManager mHeadsUpManager;
|
||||
private final ShadeController mShadeController;
|
||||
|
||||
@Inject
|
||||
public ExpandableNotificationRowDragController(Context context,
|
||||
HeadsUpManager headsUpManager) {
|
||||
HeadsUpManager headsUpManager,
|
||||
ShadeController shadeController) {
|
||||
mContext = context;
|
||||
mHeadsUpManager = headsUpManager;
|
||||
mShadeController = shadeController;
|
||||
|
||||
init();
|
||||
}
|
||||
@@ -87,6 +97,16 @@ public class ExpandableNotificationRowDragController {
|
||||
final PendingIntent contentIntent = notification.contentIntent != null
|
||||
? notification.contentIntent
|
||||
: notification.fullScreenIntent;
|
||||
if (contentIntent == null) {
|
||||
if (!enr.isPinned()) {
|
||||
// We dismiss the shade for consistency, but also because toasts currently don't
|
||||
// show above the shade
|
||||
dismissShade();
|
||||
}
|
||||
Toast.makeText(mContext, R.string.drag_split_not_supported, LENGTH_SHORT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
Bitmap iconBitmap = getBitmapFromDrawable(
|
||||
getPkgIcon(enr.getEntry().getSbn().getPackageName()));
|
||||
|
||||
@@ -97,15 +117,30 @@ public class ExpandableNotificationRowDragController {
|
||||
ClipDescription clipDescription = new ClipDescription("Drag And Drop",
|
||||
new String[]{ClipDescription.MIMETYPE_APPLICATION_ACTIVITY});
|
||||
Intent dragIntent = new Intent();
|
||||
dragIntent.putExtra("android.intent.extra.PENDING_INTENT", contentIntent);
|
||||
dragIntent.putExtra(ClipDescription.EXTRA_PENDING_INTENT, contentIntent);
|
||||
dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
|
||||
ClipData.Item item = new ClipData.Item(dragIntent);
|
||||
ClipData dragData = new ClipData(clipDescription, item);
|
||||
View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
|
||||
view.setOnDragListener(getDraggedViewDragListener());
|
||||
view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL);
|
||||
boolean result = view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL
|
||||
| View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
|
||||
if (result) {
|
||||
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
if (enr.isPinned()) {
|
||||
mHeadsUpManager.releaseAllImmediately();
|
||||
} else {
|
||||
dismissShade();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissShade() {
|
||||
// Speed up dismissing the shade since the drag needs to be handled by
|
||||
// the shell layer underneath
|
||||
mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
|
||||
false /* delayed */, 1.1f /* speedUpFactor */);
|
||||
}
|
||||
|
||||
private Drawable getPkgIcon(String pkgName) {
|
||||
Drawable pkgicon = null;
|
||||
@@ -145,16 +180,6 @@ public class ExpandableNotificationRowDragController {
|
||||
return (view, dragEvent) -> {
|
||||
switch (dragEvent.getAction()) {
|
||||
case DragEvent.ACTION_DRAG_STARTED:
|
||||
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
if (view instanceof ExpandableNotificationRow) {
|
||||
ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
|
||||
if (enr.isPinned()) {
|
||||
mHeadsUpManager.releaseAllImmediately();
|
||||
} else {
|
||||
Dependency.get(ShadeController.class).animateCollapsePanels(
|
||||
CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case DragEvent.ACTION_DRAG_ENDED:
|
||||
if (dragEvent.getResult()) {
|
||||
@@ -162,10 +187,55 @@ public class ExpandableNotificationRowDragController {
|
||||
ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
|
||||
enr.dragAndDropSuccess();
|
||||
}
|
||||
} else {
|
||||
// Fade out the drag surface in place instead of animating back to the
|
||||
// start position now that the shade is closed
|
||||
fadeOutAndRemoveDragSurface(dragEvent);
|
||||
}
|
||||
// Clear the drag listener set above
|
||||
view.setOnDragListener(null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private void fadeOutAndRemoveDragSurface(DragEvent dragEvent) {
|
||||
SurfaceControl dragSurface = dragEvent.getDragSurface();
|
||||
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
|
||||
ValueAnimator returnAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
returnAnimator.setDuration(200);
|
||||
returnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
returnAnimator.addUpdateListener(animation -> {
|
||||
float t = animation.getAnimatedFraction();
|
||||
float alpha = 1f - t;
|
||||
tx.setAlpha(dragSurface, alpha);
|
||||
tx.apply();
|
||||
});
|
||||
returnAnimator.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() {
|
||||
tx.remove(dragSurface);
|
||||
tx.apply();
|
||||
tx.close();
|
||||
}
|
||||
});
|
||||
returnAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
import static android.view.DragEvent.ACTION_DRAG_STARTED;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
@@ -36,7 +38,12 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -58,6 +65,7 @@ public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
|
||||
private NotificationMenuRow mMenuRow = mock(NotificationMenuRow.class);
|
||||
private NotificationMenuRowPlugin.MenuItem mMenuItem =
|
||||
mock(NotificationMenuRowPlugin.MenuItem.class);
|
||||
private ShadeController mShadeController = mock(ShadeController.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -69,11 +77,15 @@ public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
|
||||
mContext,
|
||||
mDependency,
|
||||
TestableLooper.get(this));
|
||||
mRow = mNotificationTestHelper.createRow();
|
||||
mRow = spy(mNotificationTestHelper.createRow());
|
||||
Notification notification = mRow.getEntry().getSbn().getNotification();
|
||||
notification.contentIntent = mock(PendingIntent.class);
|
||||
doReturn(true).when(mRow).startDragAndDrop(any(), any(), any(), anyInt());
|
||||
mGroupRow = mNotificationTestHelper.createGroup(4);
|
||||
when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
|
||||
|
||||
mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager);
|
||||
mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager,
|
||||
mShadeController);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -86,10 +98,6 @@ public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
|
||||
mRow.doLongClickCallback(0, 0);
|
||||
mRow.doDragCallback(0, 0);
|
||||
verify(controller).startDragAndDrop(mRow);
|
||||
|
||||
// Simulate the drag start
|
||||
mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
|
||||
null, null, false));
|
||||
verify(mHeadsUpManager, times(1)).releaseAllImmediately();
|
||||
}
|
||||
|
||||
@@ -98,14 +106,27 @@ public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
|
||||
ExpandableNotificationRowDragController controller = createSpyController();
|
||||
mRow.setDragController(controller);
|
||||
|
||||
mDependency.get(ShadeController.class).instantExpandNotificationsPanel();
|
||||
mRow.doDragCallback(0, 0);
|
||||
verify(controller).startDragAndDrop(mRow);
|
||||
verify(mShadeController).animateCollapsePanels(eq(0), eq(true),
|
||||
eq(false), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoStartDrag_noLaunchIntent() throws Exception {
|
||||
ExpandableNotificationRowDragController controller = createSpyController();
|
||||
mRow.setDragController(controller);
|
||||
|
||||
// Clear the intents
|
||||
Notification notification = mRow.getEntry().getSbn().getNotification();
|
||||
notification.contentIntent = null;
|
||||
notification.fullScreenIntent = null;
|
||||
|
||||
mRow.doDragCallback(0, 0);
|
||||
verify(controller).startDragAndDrop(mRow);
|
||||
|
||||
// Simulate the drag start
|
||||
mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
|
||||
null, null, false));
|
||||
verify(mDependency.get(ShadeController.class)).animateCollapsePanels(0, true);
|
||||
// Verify that we never start the actual drag since there is no content
|
||||
verify(mRow, never()).startDragAndDrop(any(), any(), any(), anyInt());
|
||||
}
|
||||
|
||||
private ExpandableNotificationRowDragController createSpyController() {
|
||||
|
||||
Reference in New Issue
Block a user