Loading src/com/android/launcher3/config/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,10 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag( "ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar."); public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag( "SECONDARY_DRAG_N_DROP_TO_PIN", false, "Enable dragging and dropping to pin apps within secondary display"); public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) { Loading src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java +13 −3 Original line number Diff line number Diff line Loading @@ -168,7 +168,10 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPrefs.unregisterOnSharedPreferenceChangeListener(this); } private void update(ItemInfo info, Function<ComponentKey, Boolean> op) { /** * Pins or unpins apps from home screen */ public void update(ItemInfo info, Function<ComponentKey, Boolean> op) { ComponentKey key = new ComponentKey(info.getTargetComponent(), info.user); if (op.apply(key)) { createFilteredAppsList(); Loading Loading @@ -210,6 +213,13 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPinnedApps.contains(new ComponentKey(info.getTargetComponent(), info.user))); } /** * Pins app to home screen */ public void addPinnedApp(ItemInfo info) { update(info, mPinnedApps::add); } private class PinUnPinShortcut extends SystemShortcut<SecondaryDisplayLauncher> { private final boolean mIsPinned; Loading src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +137 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.launcher3.secondarydisplay; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; Loading @@ -26,6 +29,9 @@ import android.view.inputmethod.InputMethodManager; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; Loading @@ -33,6 +39,11 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.AppInfo; Loading @@ -52,11 +63,11 @@ import java.util.HashMap; * Launcher activity for secondary displays */ public class SecondaryDisplayLauncher extends BaseDraggingActivity implements BgDataModel.Callbacks { implements BgDataModel.Callbacks, DragController.DragListener { private LauncherModel mModel; private BaseDragLayer mDragLayer; private SecondaryDragController mDragController; private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView; private View mAppsButton; Loading @@ -69,10 +80,13 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity private boolean mBindingItems = false; private SecondaryDisplayPredictions mSecondaryDisplayPredictions; private final int[] mTempXY = new int[2]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mModel = LauncherAppState.getInstance(this).getModel(); mDragController = new SecondaryDragController(this); mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); mSecondaryDisplayPredictions = SecondaryDisplayPredictions.newInstance(this); if (getWindow().getDecorView().isAttachedToWindow()) { Loading @@ -86,6 +100,12 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity initUi(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); this.getDragController().removeDragListener(this); } private void initUi() { if (mDragLayer != null) { return; Loading @@ -106,12 +126,19 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity mAppsView = findViewById(R.id.apps_view); mAppsButton = findViewById(R.id.all_apps_button); mDragController.addDragListener(this); mPopupDataProvider = new PopupDataProvider( mAppsView.getAppsStore()::updateNotificationDots); mModel.addCallbacksAndLoad(this); } @Override protected void onPause() { super.onPause(); mDragController.cancelDrag(); } @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); Loading @@ -129,12 +156,21 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity showAppDrawer(false); } public DragController getDragController() { return mDragController; } @Override public void onBackPressed() { if (finishAutoCancelActionMode()) { return; } if (mDragController.isDragging()) { mDragController.cancelDrag(); return; } // Note: There should be at most one log per method call. This is enforced implicitly // by using if-else statements. AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); Loading Loading @@ -236,6 +272,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity @Override public void startBinding() { mBindingItems = true; mDragController.cancelDrag(); } @Override Loading Loading @@ -308,4 +345,101 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity startActivitySafely(v, intent, item); } } /** * Core functionality for beginning a drag operation for an item that will be dropped within * the secondary display grid home screen */ public void beginDragShared(View child, DragSource source, DragOptions options) { Object dragObject = child.getTag(); if (!(dragObject instanceof ItemInfo)) { String msg = "Drag started with a view that has no tag set. This " + "will cause a crash (issue 11627249) down the line. " + "View: " + child + " tag: " + child.getTag(); throw new IllegalStateException(msg); } beginDragShared(child, source, (ItemInfo) dragObject, new DragPreviewProvider(child), options); } private void beginDragShared(View child, DragSource source, ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions options) { float iconScale = 1f; if (child instanceof BubbleTextView) { FastBitmapDrawable icon = ((BubbleTextView) child).getIcon(); if (icon != null) { iconScale = icon.getAnimatedScale(); } } // clear pressed state if necessary child.clearFocus(); child.setPressed(false); if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; icon.clearPressedBackground(); } DraggableView draggableView = null; if (child instanceof DraggableView) { draggableView = (DraggableView) child; } final View contentView = previewProvider.getContentView(); final float scale; // The draggable drawable follows the touch point around on the screen final Drawable drawable; if (contentView == null) { drawable = previewProvider.createDrawable(); scale = previewProvider.getScaleAndPosition(drawable, mTempXY); } else { drawable = null; scale = previewProvider.getScaleAndPosition(contentView, mTempXY); } int halfPadding = previewProvider.previewPadding / 2; int dragLayerX = mTempXY[0]; int dragLayerY = mTempXY[1]; Point dragVisualizeOffset = null; Rect dragRect = new Rect(); if (draggableView != null) { draggableView.getSourceVisualDragBounds(dragRect); dragLayerY += dragRect.top; dragVisualizeOffset = new Point(-halfPadding, halfPadding); } if (contentView != null) { mDragController.startDrag( contentView, draggableView, dragLayerX, dragLayerY, source, dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, options); } else { mDragController.startDrag( drawable, draggableView, dragLayerX, dragLayerY, source, dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, options); } } @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { } @Override public void onDragEnd() { } } src/com/android/launcher3/secondarydisplay/SecondaryDragController.java 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * 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.launcher3.secondarydisplay; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.View; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragDriver; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.shared.TestProtocol; /** * Drag controller for Secondary Launcher activity */ public class SecondaryDragController extends DragController<SecondaryDisplayLauncher> { private static final boolean PROFILE_DRAWING_DURING_DRAG = false; public SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher) { super(secondaryLauncher); } @Override protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view, DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options) { if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_DROP_TARGET, "5"); } if (PROFILE_DRAWING_DURING_DRAG) { android.os.Debug.startMethodTracing("Launcher"); } mActivity.hideKeyboard(); mOptions = options; if (mOptions.simulatedDndStartPoint != null) { mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x; mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y; } final int registrationX = mMotionDown.x - dragLayerX; final int registrationY = mMotionDown.y - dragLayerY; final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; mLastDropTarget = null; mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext()); mDragObject.originalView = originalView; mIsInPreDrag = mOptions.preDragCondition != null && !mOptions.preDragCondition.shouldStartDrag(0); final Resources res = mActivity.getResources(); final float scaleDps = mIsInPreDrag ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f; final DragView dragView = mDragObject.dragView = drawable != null ? new SecondaryDragView( mActivity, drawable, registrationX, registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps) : new SecondaryDragView( mActivity, view, view.getMeasuredWidth(), view.getMeasuredHeight(), registrationX, registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps); dragView.setItemInfo(dragInfo); mDragObject.dragComplete = false; mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft); mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop); mDragDriver = DragDriver.create(this, mOptions, ev -> { }); if (!mOptions.isAccessibleDrag) { mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); } mDragObject.dragSource = source; mDragObject.dragInfo = dragInfo; mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); if (dragOffset != null) { dragView.setDragVisualizeOffset(new Point(dragOffset)); } if (dragRegion != null) { dragView.setDragRegion(new Rect(dragRegion)); } mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); dragView.show(mLastTouch.x, mLastTouch.y); mDistanceSinceScroll = 0; if (!mIsInPreDrag) { callOnDragStart(); } else if (mOptions.preDragCondition != null) { mOptions.preDragCondition.onPreDragStart(mDragObject); } handleMoveEvent(mLastTouch.x, mLastTouch.y); return dragView; } @Override protected void exitDrag() { } @Override protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { DropTarget target = new DropTarget() { @Override public boolean isDropEnabled() { return true; } @Override public void onDrop(DragObject dragObject, DragOptions options) { ((SecondaryDragLayer) mActivity.getDragLayer()).getPinnedAppsAdapter().addPinnedApp( dragObject.dragInfo); dragObject.dragView.remove(); } @Override public void onDragEnter(DragObject dragObject) { if (getDistanceDragged() > mActivity.getResources().getDimensionPixelSize( R.dimen.drag_distanceThreshold)) { mActivity.showAppDrawer(false); AbstractFloatingView.closeAllOpenViews(mActivity); } } @Override public void onDragOver(DragObject dragObject) { } @Override public void onDragExit(DragObject dragObject) { } @Override public boolean acceptDrop(DragObject dragObject) { return true; } @Override public void prepareAccessibilityDrop() { } @Override public void getHitRectRelativeToDragLayer(Rect outRect) { } }; return target; } } src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +47 −2 Original line number Diff line number Diff line Loading @@ -29,8 +29,12 @@ import android.widget.GridView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; Loading Loading @@ -59,7 +63,8 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> @Override public void recreateControllers() { mControllers = new TouchController[] {new CloseAllAppsTouchController()}; mControllers = new TouchController[]{new CloseAllAppsTouchController(), mActivity.getDragController()}; } /** Loading Loading @@ -166,6 +171,10 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> } } public PinnedAppsAdapter getPinnedAppsAdapter() { return mPinnedAppsAdapter; } private boolean onIconLongClicked(View v) { if (!(v instanceof BubbleTextView)) { return false; Loading @@ -183,6 +192,7 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> if (popupDataProvider == null) { return false; } final PopupContainerWithArrow container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate( R.layout.popup_container, mActivity.getDragLayer(), false); Loading @@ -192,7 +202,42 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> Collections.emptyList(), Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v), APP_INFO.getShortcut(mActivity, item, v))); v.getParent().requestDisallowInterceptTouchEvent(true); container.requestFocus(); if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) { return true; } DragOptions options = new DragOptions(); DeviceProfile grid = mActivity.getDeviceProfile(); options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx; options.preDragCondition = container.createPreDragCondition(false); if (options.preDragCondition == null) { options.preDragCondition = new DragOptions.PreDragCondition() { private DragView<SecondaryDisplayLauncher> mDragView; @Override public boolean shouldStartDrag(double distanceDragged) { return mDragView != null && mDragView.isAnimationFinished(); } @Override public void onPreDragStart(DropTarget.DragObject dragObject) { mDragView = dragObject.dragView; if (!shouldStartDrag(0)) { mDragView.setOnAnimationEndCallback(() -> { mActivity.beginDragShared(v, mActivity.getAppsView(), options); }); } } @Override public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) { mDragView = null; } }; } mActivity.beginDragShared(v, mActivity.getAppsView(), options); return true; } } Loading
src/com/android/launcher3/config/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,10 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag( "ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar."); public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag( "SECONDARY_DRAG_N_DROP_TO_PIN", false, "Enable dragging and dropping to pin apps within secondary display"); public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) { Loading
src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java +13 −3 Original line number Diff line number Diff line Loading @@ -168,7 +168,10 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPrefs.unregisterOnSharedPreferenceChangeListener(this); } private void update(ItemInfo info, Function<ComponentKey, Boolean> op) { /** * Pins or unpins apps from home screen */ public void update(ItemInfo info, Function<ComponentKey, Boolean> op) { ComponentKey key = new ComponentKey(info.getTargetComponent(), info.user); if (op.apply(key)) { createFilteredAppsList(); Loading Loading @@ -210,6 +213,13 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPinnedApps.contains(new ComponentKey(info.getTargetComponent(), info.user))); } /** * Pins app to home screen */ public void addPinnedApp(ItemInfo info) { update(info, mPinnedApps::add); } private class PinUnPinShortcut extends SystemShortcut<SecondaryDisplayLauncher> { private final boolean mIsPinned; Loading
src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +137 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.launcher3.secondarydisplay; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; Loading @@ -26,6 +29,9 @@ import android.view.inputmethod.InputMethodManager; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; Loading @@ -33,6 +39,11 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.AppInfo; Loading @@ -52,11 +63,11 @@ import java.util.HashMap; * Launcher activity for secondary displays */ public class SecondaryDisplayLauncher extends BaseDraggingActivity implements BgDataModel.Callbacks { implements BgDataModel.Callbacks, DragController.DragListener { private LauncherModel mModel; private BaseDragLayer mDragLayer; private SecondaryDragController mDragController; private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView; private View mAppsButton; Loading @@ -69,10 +80,13 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity private boolean mBindingItems = false; private SecondaryDisplayPredictions mSecondaryDisplayPredictions; private final int[] mTempXY = new int[2]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mModel = LauncherAppState.getInstance(this).getModel(); mDragController = new SecondaryDragController(this); mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); mSecondaryDisplayPredictions = SecondaryDisplayPredictions.newInstance(this); if (getWindow().getDecorView().isAttachedToWindow()) { Loading @@ -86,6 +100,12 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity initUi(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); this.getDragController().removeDragListener(this); } private void initUi() { if (mDragLayer != null) { return; Loading @@ -106,12 +126,19 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity mAppsView = findViewById(R.id.apps_view); mAppsButton = findViewById(R.id.all_apps_button); mDragController.addDragListener(this); mPopupDataProvider = new PopupDataProvider( mAppsView.getAppsStore()::updateNotificationDots); mModel.addCallbacksAndLoad(this); } @Override protected void onPause() { super.onPause(); mDragController.cancelDrag(); } @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); Loading @@ -129,12 +156,21 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity showAppDrawer(false); } public DragController getDragController() { return mDragController; } @Override public void onBackPressed() { if (finishAutoCancelActionMode()) { return; } if (mDragController.isDragging()) { mDragController.cancelDrag(); return; } // Note: There should be at most one log per method call. This is enforced implicitly // by using if-else statements. AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); Loading Loading @@ -236,6 +272,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity @Override public void startBinding() { mBindingItems = true; mDragController.cancelDrag(); } @Override Loading Loading @@ -308,4 +345,101 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity startActivitySafely(v, intent, item); } } /** * Core functionality for beginning a drag operation for an item that will be dropped within * the secondary display grid home screen */ public void beginDragShared(View child, DragSource source, DragOptions options) { Object dragObject = child.getTag(); if (!(dragObject instanceof ItemInfo)) { String msg = "Drag started with a view that has no tag set. This " + "will cause a crash (issue 11627249) down the line. " + "View: " + child + " tag: " + child.getTag(); throw new IllegalStateException(msg); } beginDragShared(child, source, (ItemInfo) dragObject, new DragPreviewProvider(child), options); } private void beginDragShared(View child, DragSource source, ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions options) { float iconScale = 1f; if (child instanceof BubbleTextView) { FastBitmapDrawable icon = ((BubbleTextView) child).getIcon(); if (icon != null) { iconScale = icon.getAnimatedScale(); } } // clear pressed state if necessary child.clearFocus(); child.setPressed(false); if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; icon.clearPressedBackground(); } DraggableView draggableView = null; if (child instanceof DraggableView) { draggableView = (DraggableView) child; } final View contentView = previewProvider.getContentView(); final float scale; // The draggable drawable follows the touch point around on the screen final Drawable drawable; if (contentView == null) { drawable = previewProvider.createDrawable(); scale = previewProvider.getScaleAndPosition(drawable, mTempXY); } else { drawable = null; scale = previewProvider.getScaleAndPosition(contentView, mTempXY); } int halfPadding = previewProvider.previewPadding / 2; int dragLayerX = mTempXY[0]; int dragLayerY = mTempXY[1]; Point dragVisualizeOffset = null; Rect dragRect = new Rect(); if (draggableView != null) { draggableView.getSourceVisualDragBounds(dragRect); dragLayerY += dragRect.top; dragVisualizeOffset = new Point(-halfPadding, halfPadding); } if (contentView != null) { mDragController.startDrag( contentView, draggableView, dragLayerX, dragLayerY, source, dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, options); } else { mDragController.startDrag( drawable, draggableView, dragLayerX, dragLayerY, source, dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, options); } } @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { } @Override public void onDragEnd() { } }
src/com/android/launcher3/secondarydisplay/SecondaryDragController.java 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * 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.launcher3.secondarydisplay; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.View; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragDriver; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.shared.TestProtocol; /** * Drag controller for Secondary Launcher activity */ public class SecondaryDragController extends DragController<SecondaryDisplayLauncher> { private static final boolean PROFILE_DRAWING_DURING_DRAG = false; public SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher) { super(secondaryLauncher); } @Override protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view, DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options) { if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_DROP_TARGET, "5"); } if (PROFILE_DRAWING_DURING_DRAG) { android.os.Debug.startMethodTracing("Launcher"); } mActivity.hideKeyboard(); mOptions = options; if (mOptions.simulatedDndStartPoint != null) { mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x; mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y; } final int registrationX = mMotionDown.x - dragLayerX; final int registrationY = mMotionDown.y - dragLayerY; final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; mLastDropTarget = null; mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext()); mDragObject.originalView = originalView; mIsInPreDrag = mOptions.preDragCondition != null && !mOptions.preDragCondition.shouldStartDrag(0); final Resources res = mActivity.getResources(); final float scaleDps = mIsInPreDrag ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f; final DragView dragView = mDragObject.dragView = drawable != null ? new SecondaryDragView( mActivity, drawable, registrationX, registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps) : new SecondaryDragView( mActivity, view, view.getMeasuredWidth(), view.getMeasuredHeight(), registrationX, registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps); dragView.setItemInfo(dragInfo); mDragObject.dragComplete = false; mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft); mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop); mDragDriver = DragDriver.create(this, mOptions, ev -> { }); if (!mOptions.isAccessibleDrag) { mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); } mDragObject.dragSource = source; mDragObject.dragInfo = dragInfo; mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); if (dragOffset != null) { dragView.setDragVisualizeOffset(new Point(dragOffset)); } if (dragRegion != null) { dragView.setDragRegion(new Rect(dragRegion)); } mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); dragView.show(mLastTouch.x, mLastTouch.y); mDistanceSinceScroll = 0; if (!mIsInPreDrag) { callOnDragStart(); } else if (mOptions.preDragCondition != null) { mOptions.preDragCondition.onPreDragStart(mDragObject); } handleMoveEvent(mLastTouch.x, mLastTouch.y); return dragView; } @Override protected void exitDrag() { } @Override protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { DropTarget target = new DropTarget() { @Override public boolean isDropEnabled() { return true; } @Override public void onDrop(DragObject dragObject, DragOptions options) { ((SecondaryDragLayer) mActivity.getDragLayer()).getPinnedAppsAdapter().addPinnedApp( dragObject.dragInfo); dragObject.dragView.remove(); } @Override public void onDragEnter(DragObject dragObject) { if (getDistanceDragged() > mActivity.getResources().getDimensionPixelSize( R.dimen.drag_distanceThreshold)) { mActivity.showAppDrawer(false); AbstractFloatingView.closeAllOpenViews(mActivity); } } @Override public void onDragOver(DragObject dragObject) { } @Override public void onDragExit(DragObject dragObject) { } @Override public boolean acceptDrop(DragObject dragObject) { return true; } @Override public void prepareAccessibilityDrop() { } @Override public void getHitRectRelativeToDragLayer(Rect outRect) { } }; return target; } }
src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +47 −2 Original line number Diff line number Diff line Loading @@ -29,8 +29,12 @@ import android.widget.GridView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; Loading Loading @@ -59,7 +63,8 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> @Override public void recreateControllers() { mControllers = new TouchController[] {new CloseAllAppsTouchController()}; mControllers = new TouchController[]{new CloseAllAppsTouchController(), mActivity.getDragController()}; } /** Loading Loading @@ -166,6 +171,10 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> } } public PinnedAppsAdapter getPinnedAppsAdapter() { return mPinnedAppsAdapter; } private boolean onIconLongClicked(View v) { if (!(v instanceof BubbleTextView)) { return false; Loading @@ -183,6 +192,7 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> if (popupDataProvider == null) { return false; } final PopupContainerWithArrow container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate( R.layout.popup_container, mActivity.getDragLayer(), false); Loading @@ -192,7 +202,42 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> Collections.emptyList(), Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v), APP_INFO.getShortcut(mActivity, item, v))); v.getParent().requestDisallowInterceptTouchEvent(true); container.requestFocus(); if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) { return true; } DragOptions options = new DragOptions(); DeviceProfile grid = mActivity.getDeviceProfile(); options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx; options.preDragCondition = container.createPreDragCondition(false); if (options.preDragCondition == null) { options.preDragCondition = new DragOptions.PreDragCondition() { private DragView<SecondaryDisplayLauncher> mDragView; @Override public boolean shouldStartDrag(double distanceDragged) { return mDragView != null && mDragView.isAnimationFinished(); } @Override public void onPreDragStart(DropTarget.DragObject dragObject) { mDragView = dragObject.dragView; if (!shouldStartDrag(0)) { mDragView.setOnAnimationEndCallback(() -> { mActivity.beginDragShared(v, mActivity.getAppsView(), options); }); } } @Override public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) { mDragView = null; } }; } mActivity.beginDragShared(v, mActivity.getAppsView(), options); return true; } }