Merge "Removing Launcher dependency from Folders" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b32fd46c8d
@@ -491,7 +491,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
List<View> viewsToAnimate = new ArrayList<>();
|
||||
|
||||
Workspace workspace = mLauncher.getWorkspace();
|
||||
workspace.getVisiblePages().forEach(
|
||||
workspace.forEachVisiblePage(
|
||||
view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
|
||||
|
||||
viewsToAnimate.add(mLauncher.getHotseat());
|
||||
|
||||
@@ -16,12 +16,24 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import android.content.ContextWrapper;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
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.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
|
||||
@@ -35,6 +47,7 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo
|
||||
private final DeviceProfile mDeviceProfile;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final TaskbarContainerView mTaskbarContainerView;
|
||||
private final MyDragController mDragController;
|
||||
|
||||
public TaskbarActivityContext(BaseQuickstepLauncher launcher) {
|
||||
super(launcher);
|
||||
@@ -47,6 +60,7 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo
|
||||
|
||||
mTaskbarContainerView = (TaskbarContainerView) mLayoutInflater
|
||||
.inflate(R.layout.taskbar, null, false);
|
||||
mDragController = new MyDragController(this);
|
||||
}
|
||||
|
||||
public TaskbarContainerView getTaskbarContainerView() {
|
||||
@@ -72,4 +86,31 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo
|
||||
public Rect getFolderBoundingBox() {
|
||||
return mTaskbarContainerView.getFolderBoundingBox();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DragController getDragController() {
|
||||
return mDragController;
|
||||
}
|
||||
|
||||
private static class MyDragController extends DragController<TaskbarActivityContext> {
|
||||
MyDragController(TaskbarActivityContext activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@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) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitDrag() { }
|
||||
|
||||
@Override
|
||||
protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,7 @@ public class StaggeredWorkspaceAnim {
|
||||
int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
|
||||
|
||||
// Add animation for all the visible workspace pages
|
||||
workspace.getVisiblePages()
|
||||
.forEach(page -> addAnimationForPage((CellLayout) page, totalRows));
|
||||
workspace.forEachVisiblePage(page -> addAnimationForPage((CellLayout) page, totalRows));
|
||||
|
||||
boolean workspaceClipChildren = workspace.getClipChildren();
|
||||
boolean workspaceClipToPadding = workspace.getClipToPadding();
|
||||
|
||||
@@ -132,6 +132,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
|
||||
|
||||
private final ViewCache mViewCache = new ViewCache();
|
||||
|
||||
@Override
|
||||
public ViewCache getViewCache() {
|
||||
return mViewCache;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.util.UiThreadHelper.hideKeyboardAsync;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
@@ -25,7 +27,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
|
||||
/**
|
||||
@@ -99,7 +101,7 @@ public class ExtendedEditText extends EditText {
|
||||
}
|
||||
|
||||
public void hideKeyboard() {
|
||||
UiThreadHelper.hideKeyboardAsync(Launcher.getLauncher(getContext()), getWindowToken());
|
||||
hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getWindowToken());
|
||||
}
|
||||
|
||||
private boolean showSoftInput() {
|
||||
|
||||
@@ -124,6 +124,7 @@ import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.dragndrop.DragView;
|
||||
import com.android.launcher3.dragndrop.LauncherDragController;
|
||||
import com.android.launcher3.folder.FolderGridOrganizer;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
@@ -428,7 +429,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
mIconCache = app.getIconCache();
|
||||
mAccessibilityDelegate = createAccessibilityDelegate();
|
||||
|
||||
mDragController = new DragController(this);
|
||||
mDragController = new LauncherDragController(this);
|
||||
mAllAppsController = new AllAppsTransitionController(this);
|
||||
mStateManager = new StateManager<>(this, NORMAL);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An abstraction of the original Workspace which supports browsing through a
|
||||
@@ -295,18 +295,16 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently visible pages.
|
||||
* Executes the callback against each visible page
|
||||
*/
|
||||
public Iterable<View> getVisiblePages() {
|
||||
public void forEachVisiblePage(Consumer<View> callback) {
|
||||
int panelCount = getPanelCount();
|
||||
List<View> visiblePages = new ArrayList<>(panelCount);
|
||||
for (int i = mCurrentPage; i < mCurrentPage + panelCount; i++) {
|
||||
View page = getPageAt(i);
|
||||
if (page != null) {
|
||||
visiblePages.add(page);
|
||||
callback.accept(page);
|
||||
}
|
||||
}
|
||||
return visiblePages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1034,7 +1032,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
// Try canceling the long press. It could also have been scheduled
|
||||
// by a distant descendant, so use the mAllowLongPress flag to block
|
||||
// everything
|
||||
getVisiblePages().forEach(View::cancelLongPress);
|
||||
forEachVisiblePage(View::cancelLongPress);
|
||||
}
|
||||
|
||||
protected float getScrollProgress(int screenCenter, View v, int page) {
|
||||
|
||||
@@ -2974,7 +2974,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
|
||||
cellLayouts.add(getHotseat());
|
||||
getVisiblePages().forEach(page -> cellLayouts.add((CellLayout) page));
|
||||
forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));
|
||||
|
||||
// Order: App icons, app in folder. Items in hotseat get returned first.
|
||||
if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
|
||||
|
||||
@@ -16,45 +16,37 @@
|
||||
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.Utilities.ATLEAST_Q;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
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.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Class for initiating a drag within a view or across multiple views.
|
||||
* @param <T>
|
||||
*/
|
||||
public class DragController implements DragDriver.EventListener, TouchController {
|
||||
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
|
||||
public abstract class DragController<T extends ActivityContext>
|
||||
implements DragDriver.EventListener, TouchController {
|
||||
|
||||
/**
|
||||
* When a drag is started from a deep press, you need to drag this much farther than normal to
|
||||
@@ -62,8 +54,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
*/
|
||||
private static final int DEEP_PRESS_DISTANCE_FACTOR = 3;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final FlingToDeleteHelper mFlingToDeleteHelper;
|
||||
protected final T mActivity;
|
||||
|
||||
// temporaries to avoid gc thrash
|
||||
private final Rect mRectTemp = new Rect();
|
||||
@@ -73,30 +64,30 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
* Drag driver for the current drag/drop operation, or null if there is no active DND operation.
|
||||
* It's null during accessible drag operations.
|
||||
*/
|
||||
private DragDriver mDragDriver = null;
|
||||
protected DragDriver mDragDriver = null;
|
||||
|
||||
/** Options controlling the drag behavior. */
|
||||
private DragOptions mOptions;
|
||||
protected DragOptions mOptions;
|
||||
|
||||
/** Coordinate for motion down event */
|
||||
private final Point mMotionDown = new Point();
|
||||
protected final Point mMotionDown = new Point();
|
||||
/** Coordinate for last touch event **/
|
||||
private final Point mLastTouch = new Point();
|
||||
protected final Point mLastTouch = new Point();
|
||||
|
||||
private final Point mTmpPoint = new Point();
|
||||
|
||||
private DropTarget.DragObject mDragObject;
|
||||
protected DropTarget.DragObject mDragObject;
|
||||
|
||||
/** Who can receive drop events */
|
||||
private final ArrayList<DropTarget> mDropTargets = new ArrayList<>();
|
||||
private final ArrayList<DragListener> mListeners = new ArrayList<>();
|
||||
|
||||
private DropTarget mLastDropTarget;
|
||||
protected DropTarget mLastDropTarget;
|
||||
|
||||
private int mLastTouchClassification;
|
||||
private int mDistanceSinceScroll = 0;
|
||||
protected int mDistanceSinceScroll = 0;
|
||||
|
||||
private boolean mIsInPreDrag;
|
||||
protected boolean mIsInPreDrag;
|
||||
|
||||
/**
|
||||
* Interface to receive notifications when a drag starts or stops
|
||||
@@ -119,9 +110,8 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
/**
|
||||
* Used to create a new DragLayer from XML.
|
||||
*/
|
||||
public DragController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mFlingToDeleteHelper = new FlingToDeleteHelper(launcher);
|
||||
public DragController(T activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +188,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
options);
|
||||
}
|
||||
|
||||
private DragView startDrag(
|
||||
protected abstract DragView startDrag(
|
||||
@Nullable Drawable drawable,
|
||||
@Nullable View view,
|
||||
DraggableView originalView,
|
||||
@@ -210,98 +200,9 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
Rect dragRegion,
|
||||
float initialDragViewScale,
|
||||
float dragViewScaleOnDrop,
|
||||
DragOptions options) {
|
||||
if (PROFILE_DRAWING_DURING_DRAG) {
|
||||
android.os.Debug.startMethodTracing("Launcher");
|
||||
}
|
||||
DragOptions options);
|
||||
|
||||
mLauncher.hideKeyboard();
|
||||
AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
|
||||
|
||||
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(mLauncher.getApplicationContext());
|
||||
mDragObject.originalView = originalView;
|
||||
|
||||
mIsInPreDrag = mOptions.preDragCondition != null
|
||||
&& !mOptions.preDragCondition.shouldStartDrag(0);
|
||||
|
||||
final Resources res = mLauncher.getResources();
|
||||
final float scaleDps = mIsInPreDrag
|
||||
? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
|
||||
final DragView dragView = mDragObject.dragView = drawable != null
|
||||
? new DragView(
|
||||
mLauncher,
|
||||
drawable,
|
||||
registrationX,
|
||||
registrationY,
|
||||
initialDragViewScale,
|
||||
dragViewScaleOnDrop,
|
||||
scaleDps)
|
||||
: new DragView(
|
||||
mLauncher,
|
||||
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, mFlingToDeleteHelper::recordMotionEvent);
|
||||
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));
|
||||
}
|
||||
|
||||
mLauncher.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);
|
||||
|
||||
if (!mLauncher.isTouchInProgress() && options.simulatedDndStartPoint == null) {
|
||||
// If it is an internal drag and the touch is already complete, cancel immediately
|
||||
MAIN_EXECUTOR.submit(this::cancelDrag);
|
||||
}
|
||||
return dragView;
|
||||
}
|
||||
|
||||
private void callOnDragStart() {
|
||||
protected void callOnDragStart() {
|
||||
if (mOptions.preDragCondition != null) {
|
||||
mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/);
|
||||
}
|
||||
@@ -357,13 +258,15 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
if (!accepted) {
|
||||
// If it was not accepted, cleanup the state. If it was accepted, it is the
|
||||
// responsibility of the drop target to cleanup the state.
|
||||
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
|
||||
exitDrag();
|
||||
mDragObject.deferDragViewCleanupPostAnimation = false;
|
||||
}
|
||||
|
||||
mDragObject.dragSource.onDropCompleted(dropTarget, mDragObject, accepted);
|
||||
}
|
||||
|
||||
protected abstract void exitDrag();
|
||||
|
||||
public void onAppsRemoved(ItemInfoMatcher matcher) {
|
||||
// Cancel the current drag if we are removing an app that we are dragging
|
||||
if (mDragObject != null) {
|
||||
@@ -377,7 +280,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
}
|
||||
}
|
||||
|
||||
private void endDrag() {
|
||||
protected void endDrag() {
|
||||
if (isDragging()) {
|
||||
mDragDriver = null;
|
||||
boolean isDeferred = false;
|
||||
@@ -396,8 +299,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
callOnDragEnd();
|
||||
}
|
||||
}
|
||||
|
||||
mFlingToDeleteHelper.releaseVelocityTracker();
|
||||
}
|
||||
|
||||
public void animateDragViewToOriginalPosition(final Runnable onComplete,
|
||||
@@ -443,7 +344,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
* Clamps the position to the drag layer bounds.
|
||||
*/
|
||||
private Point getClampedDragLayerPos(float x, float y) {
|
||||
mLauncher.getDragLayer().getLocalVisibleRect(mRectTemp);
|
||||
mActivity.getDragLayer().getLocalVisibleRect(mRectTemp);
|
||||
mTmpPoint.x = (int) Math.max(mRectTemp.left, Math.min(x, mRectTemp.right - 1));
|
||||
mTmpPoint.y = (int) Math.max(mRectTemp.top, Math.min(y, mRectTemp.bottom - 1));
|
||||
return mTmpPoint;
|
||||
@@ -465,19 +366,16 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
@Override
|
||||
public void onDriverDragEnd(float x, float y) {
|
||||
DropTarget dropTarget;
|
||||
Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions);
|
||||
if (flingAnimation != null) {
|
||||
dropTarget = mFlingToDeleteHelper.getDropTarget();
|
||||
} else {
|
||||
dropTarget = findDropTarget((int) x, (int) y, mCoordinatesTemp);
|
||||
if (!endWithFlingAnimation()) {
|
||||
drop(findDropTarget((int) x, (int) y, mCoordinatesTemp), null);
|
||||
}
|
||||
|
||||
drop(dropTarget, flingAnimation);
|
||||
|
||||
endDrag();
|
||||
}
|
||||
|
||||
protected boolean endWithFlingAnimation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDriverDragCancel() {
|
||||
cancelDrag();
|
||||
@@ -520,7 +418,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
return mDragDriver != null && mDragDriver.onDragEvent(event);
|
||||
}
|
||||
|
||||
private void handleMoveEvent(int x, int y) {
|
||||
protected void handleMoveEvent(int x, int y) {
|
||||
mDragObject.dragView.move(x, y);
|
||||
|
||||
// Drop on someone?
|
||||
@@ -592,7 +490,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
endDrag();
|
||||
}
|
||||
|
||||
private void drop(DropTarget dropTarget, Runnable flingAnimation) {
|
||||
protected void drop(DropTarget dropTarget, Runnable flingAnimation) {
|
||||
final int[] coordinates = mCoordinatesTemp;
|
||||
mDragObject.x = coordinates[0];
|
||||
mDragObject.y = coordinates[1];
|
||||
@@ -649,7 +547,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
if (r.contains(x, y)) {
|
||||
dropCoordinates[0] = x;
|
||||
dropCoordinates[1] = y;
|
||||
mLauncher.getDragLayer().mapCoordInSelfToDescendant((View) target, dropCoordinates);
|
||||
mActivity.getDragLayer().mapCoordInSelfToDescendant((View) target, dropCoordinates);
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -657,11 +555,11 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
// cell layout to drop to in the existing drag/drop logic.
|
||||
dropCoordinates[0] = x;
|
||||
dropCoordinates[1] = y;
|
||||
mLauncher.getDragLayer().mapCoordInSelfToDescendant(mLauncher.getWorkspace(),
|
||||
dropCoordinates);
|
||||
return mLauncher.getWorkspace();
|
||||
return getDefaultDropTarget(dropCoordinates);
|
||||
}
|
||||
|
||||
protected abstract DropTarget getDefaultDropTarget(int[] dropCoordinates);
|
||||
|
||||
/**
|
||||
* Sets the drag listener which will be notified when a drag starts or ends.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
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.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
|
||||
/**
|
||||
* Drag controller for Launcher activity
|
||||
*/
|
||||
public class LauncherDragController extends DragController<Launcher> {
|
||||
|
||||
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
|
||||
|
||||
private final FlingToDeleteHelper mFlingToDeleteHelper;
|
||||
|
||||
public LauncherDragController(Launcher launcher) {
|
||||
super(launcher);
|
||||
mFlingToDeleteHelper = new FlingToDeleteHelper(launcher);
|
||||
}
|
||||
|
||||
@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 (PROFILE_DRAWING_DURING_DRAG) {
|
||||
android.os.Debug.startMethodTracing("Launcher");
|
||||
}
|
||||
|
||||
mActivity.hideKeyboard();
|
||||
AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_DISCOVERY_BOUNCE);
|
||||
|
||||
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 DragView(
|
||||
mActivity,
|
||||
drawable,
|
||||
registrationX,
|
||||
registrationY,
|
||||
initialDragViewScale,
|
||||
dragViewScaleOnDrop,
|
||||
scaleDps)
|
||||
: new DragView(
|
||||
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, mFlingToDeleteHelper::recordMotionEvent);
|
||||
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);
|
||||
|
||||
if (!mActivity.isTouchInProgress() && options.simulatedDndStartPoint == null) {
|
||||
// If it is an internal drag and the touch is already complete, cancel immediately
|
||||
MAIN_EXECUTOR.submit(this::cancelDrag);
|
||||
}
|
||||
return dragView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitDrag() {
|
||||
mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean endWithFlingAnimation() {
|
||||
Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions);
|
||||
if (flingAnimation != null) {
|
||||
drop(mFlingToDeleteHelper.getDropTarget(), flingAnimation);
|
||||
return true;
|
||||
}
|
||||
return super.endWithFlingAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endDrag() {
|
||||
super.endDrag();
|
||||
mFlingToDeleteHelper.releaseVelocityTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
|
||||
mActivity.getDragLayer().mapCoordInSelfToDescendant(mActivity.getWorkspace(),
|
||||
dropCoordinates);
|
||||
return mActivity.getWorkspace();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
|
||||
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
|
||||
@@ -109,7 +108,6 @@ import com.android.launcher3.widget.LocalColorExtractor;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
@@ -177,8 +175,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
private boolean mIsAnimatingClosed = false;
|
||||
|
||||
// Folder can be displayed in Launcher's activity or a separate window (e.g. Taskbar).
|
||||
// Anything specific to Launcher should use mLauncher, otherwise should use mActivityContext.
|
||||
protected final Launcher mLauncher;
|
||||
// Anything specific to Launcher should use mLauncherDelegate, otherwise should
|
||||
// use mActivityContext.
|
||||
protected final LauncherDelegate mLauncherDelegate;
|
||||
protected final ActivityContext mActivityContext;
|
||||
|
||||
protected DragController mDragController;
|
||||
@@ -235,8 +234,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
// Wallpaper local color extraction
|
||||
@Nullable private LocalColorExtractor mColorExtractor;
|
||||
@Nullable private LocalColorExtractor.Listener mColorListener;
|
||||
private final Rect mTempRect = new Rect();
|
||||
private final RectF mTempRectF = new RectF();
|
||||
|
||||
// For simplicity, we start the color change only after the open animation has started.
|
||||
private Runnable mColorChangeRunnable;
|
||||
@@ -255,8 +252,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
super(context, attrs);
|
||||
setAlwaysDrawnWithCacheEnabled(false);
|
||||
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mActivityContext = ActivityContext.lookupContext(context);
|
||||
mLauncherDelegate = LauncherDelegate.from(mActivityContext);
|
||||
|
||||
mStatsLogManager = StatsLogManager.newInstance(context);
|
||||
// We need this view to be focusable in touch mode so that when text editing of the folder
|
||||
// name is complete, we have something to focus on, thus hiding the cursor and giving
|
||||
@@ -267,7 +265,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
final DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
final DeviceProfile dp = mActivityContext.getDeviceProfile();
|
||||
final int paddingLeftRight = dp.folderContentPaddingLeftRight;
|
||||
|
||||
mContent = findViewById(R.id.folder_content);
|
||||
@@ -298,7 +296,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
if (Utilities.ATLEAST_S) {
|
||||
mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
|
||||
mColorExtractor = LocalColorExtractor.newInstance(getContext());
|
||||
mColorListener = (RectF rect, SparseIntArray extractedColors) -> {
|
||||
mColorChangeRunnable = () -> {
|
||||
mColorChangeRunnable = null;
|
||||
@@ -339,7 +337,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
public boolean onLongClick(View v) {
|
||||
// Return if global dragging is not enabled
|
||||
if (!mLauncher.isDraggingEnabled()) return true;
|
||||
if (!mLauncherDelegate.isDraggingEnabled()) return true;
|
||||
return startDrag(v, new DragOptions());
|
||||
}
|
||||
|
||||
@@ -365,7 +363,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
});
|
||||
}
|
||||
|
||||
mLauncher.getWorkspace().beginDragShared(v, this, options);
|
||||
mLauncherDelegate.beginDragShared(v, this, options);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -421,7 +419,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onBackKey newTitle=" + newTitle);
|
||||
}
|
||||
mInfo.setTitle(newTitle, mLauncher.getModelWriter());
|
||||
mInfo.setTitle(newTitle, mLauncherDelegate.getModelWriter());
|
||||
mFolderIcon.onTitleChanged(newTitle);
|
||||
|
||||
if (TextUtils.isEmpty(mInfo.title)) {
|
||||
@@ -486,6 +484,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
public void setFolderIcon(FolderIcon icon) {
|
||||
mFolderIcon = icon;
|
||||
mLauncherDelegate.init(this, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -592,8 +591,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
private void startAnimation(final AnimatorSet a) {
|
||||
mLauncher.getWorkspace().getVisiblePages()
|
||||
.forEach(visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
|
||||
mLauncherDelegate.forEachVisibleWorkspacePage(
|
||||
visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
|
||||
|
||||
a.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
@@ -754,12 +753,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
|
||||
.translationX(0)
|
||||
.setInterpolator(AnimationUtils.loadInterpolator(
|
||||
mLauncher, android.R.interpolator.fast_out_slow_in));
|
||||
getContext(), android.R.interpolator.fast_out_slow_in));
|
||||
mPageIndicator.playEntryAnimation();
|
||||
|
||||
if (updateAnimationFlag) {
|
||||
mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true,
|
||||
mLauncher.getModelWriter());
|
||||
mLauncherDelegate.getModelWriter());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1115,7 +1114,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
if (getItemCount() <= mContent.itemsPerPage()) {
|
||||
// Show the animation, next time something is added to the folder.
|
||||
mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false,
|
||||
mLauncher.getModelWriter());
|
||||
mLauncherDelegate.getModelWriter());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1133,7 +1132,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
mLauncher.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0);
|
||||
mLauncherDelegate.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0);
|
||||
}
|
||||
if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && !isBind
|
||||
&& total > 1 /* no need to update if there's one icon */) {
|
||||
@@ -1190,12 +1189,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
if (mColorExtractor != null) {
|
||||
mColorExtractor.removeLocations();
|
||||
mColorExtractor.setListener(mColorListener);
|
||||
mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
|
||||
mColorExtractor.getExtractedRectForViewRect(mLauncher,
|
||||
mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
|
||||
if (!mTempRectF.isEmpty()) {
|
||||
mColorExtractor.addLocation(Arrays.asList(mTempRectF));
|
||||
}
|
||||
mLauncherDelegate.addRectForColorExtraction(lp, mColorExtractor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,7 +1230,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
if (mContent.getChildCount() > 0) {
|
||||
int cellIconGap = (mContent.getPageAt(0).getCellWidth()
|
||||
- mLauncher.getDeviceProfile().iconSizePx) / 2;
|
||||
- mActivityContext.getDeviceProfile().iconSizePx) / 2;
|
||||
mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap,
|
||||
mFooter.getPaddingTop(),
|
||||
mContent.getPaddingRight() + cellIconGap,
|
||||
@@ -1266,56 +1260,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
@Thunk void replaceFolderWithFinalItem() {
|
||||
// Add the last remaining child to the workspace in place of the folder
|
||||
Runnable onCompleteRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int itemCount = getItemCount();
|
||||
if (itemCount <= 1) {
|
||||
View newIcon = null;
|
||||
WorkspaceItemInfo finalItem = null;
|
||||
|
||||
if (itemCount == 1) {
|
||||
// Move the item from the folder to the workspace, in the position of the
|
||||
// folder
|
||||
CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container,
|
||||
mInfo.screenId);
|
||||
finalItem = mInfo.contents.remove(0);
|
||||
newIcon = mLauncher.createShortcut(cellLayout, finalItem);
|
||||
mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
|
||||
mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY);
|
||||
}
|
||||
|
||||
// Remove the folder
|
||||
mLauncher.removeItem(mFolderIcon, mInfo, true /* deleteFromDb */);
|
||||
if (mFolderIcon instanceof DropTarget) {
|
||||
mDragController.removeDropTarget((DropTarget) mFolderIcon);
|
||||
}
|
||||
|
||||
if (newIcon != null) {
|
||||
// We add the child after removing the folder to prevent both from existing
|
||||
// at the same time in the CellLayout. We need to add the new item with
|
||||
// addInScreenFromBind() to ensure that hotseat items are placed correctly.
|
||||
mLauncher.getWorkspace().addInScreenFromBind(newIcon, mInfo);
|
||||
|
||||
// Focus the newly created child
|
||||
newIcon.requestFocus();
|
||||
}
|
||||
if (finalItem != null) {
|
||||
StatsLogger logger = mStatsLogManager.logger().withItemInfo(finalItem);
|
||||
mDragController.getLogInstanceId().map(logger::withInstanceId)
|
||||
.orElse(logger)
|
||||
.log(LAUNCHER_FOLDER_CONVERTED_TO_ICON);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
View finalChild = mContent.getLastItem();
|
||||
if (finalChild != null) {
|
||||
mFolderIcon.performDestroyAnimation(onCompleteRunnable);
|
||||
} else {
|
||||
onCompleteRunnable.run();
|
||||
}
|
||||
mLauncherDelegate.replaceFolderWithFinalItem(this);
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
@@ -1374,6 +1319,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mScrollPauseAlarm.cancelAlarm();
|
||||
}
|
||||
mContent.completePendingPageChanges();
|
||||
Launcher launcher = mLauncherDelegate.getLauncher();
|
||||
if (launcher == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
|
||||
? (PendingAddShortcutInfo) d.dragInfo : null;
|
||||
@@ -1383,7 +1332,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
pasi.container = mInfo.id;
|
||||
pasi.rank = mEmptyCellRank;
|
||||
|
||||
mLauncher.addPendingItem(pasi, pasi.container, pasi.screenId, null, pasi.spanX,
|
||||
launcher.addPendingItem(pasi, pasi.container, pasi.screenId, null, pasi.spanX,
|
||||
pasi.spanY);
|
||||
d.deferDragViewCleanupPostAnimation = false;
|
||||
mRearrangeOnClose = true;
|
||||
@@ -1405,7 +1354,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
// Actually move the item in the database if it was an external drag. Call this
|
||||
// before creating the view, so that WorkspaceItemInfo is updated appropriately.
|
||||
mLauncher.getModelWriter().addOrMoveItemInDatabase(
|
||||
mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(
|
||||
si, mInfo.id, 0, si.cellX, si.cellY);
|
||||
mIsExternalDrag = false;
|
||||
} else {
|
||||
@@ -1420,7 +1369,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
float scaleY = getScaleY();
|
||||
setScaleX(1.0f);
|
||||
setScaleY(1.0f);
|
||||
mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView, null);
|
||||
launcher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView, null);
|
||||
setScaleX(scaleX);
|
||||
setScaleY(scaleY);
|
||||
} else {
|
||||
@@ -1448,10 +1397,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
if (mContent.getPageCount() > 1) {
|
||||
// The animation has already been shown while opening the folder.
|
||||
mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher.getModelWriter());
|
||||
mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true,
|
||||
mLauncherDelegate.getModelWriter());
|
||||
}
|
||||
|
||||
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
|
||||
launcher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
|
||||
if (d.stateAnnouncer != null) {
|
||||
d.stateAnnouncer.completeAction(R.string.item_moved);
|
||||
}
|
||||
@@ -1480,7 +1430,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
FolderGridOrganizer verifier = new FolderGridOrganizer(
|
||||
mActivityContext.getDeviceProfile().inv).setFolderInfo(mInfo);
|
||||
verifier.updateRankAndPos(item, rank);
|
||||
mLauncher.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
|
||||
mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
|
||||
item.cellY);
|
||||
updateItemLocationsInDatabaseBatch(false);
|
||||
|
||||
@@ -1713,17 +1663,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (!dl.isEventOverView(this, ev)) {
|
||||
if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
|
||||
// Do not close the container if in drag and drop.
|
||||
if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// TODO: add ww log if need to gather tap outside to close folder
|
||||
close(true);
|
||||
return true;
|
||||
}
|
||||
} else if (!dl.isEventOverView(this, ev)
|
||||
&& mLauncherDelegate.interceptOutsideTouch(ev, dl, this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -169,14 +169,11 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
public static <T extends Context & ActivityContext> FolderIcon inflateFolderAndIcon(int resId,
|
||||
T activityContext, ViewGroup group, FolderInfo folderInfo) {
|
||||
Folder folder = Folder.fromXml(activityContext);
|
||||
folder.setDragController(folder.mLauncher.getDragController());
|
||||
|
||||
FolderIcon icon = inflateIcon(resId, activityContext, group, folderInfo);
|
||||
folder.setFolderIcon(icon);
|
||||
folder.bind(folderInfo);
|
||||
icon.setFolder(folder);
|
||||
|
||||
icon.setOnFocusChangeListener(folder.mLauncher.getFocusHandler());
|
||||
icon.mBackground.paddingY = icon.isInHotseat()
|
||||
? 0 : activityContext.getDeviceProfile().cellYPaddingPx;
|
||||
return icon;
|
||||
@@ -467,7 +464,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
CharSequence newTitle = nameInfos.getLabels()[0];
|
||||
FromState fromState = mInfo.getFromLabelState();
|
||||
|
||||
mInfo.setTitle(newTitle, mFolder.mLauncher.getModelWriter());
|
||||
mInfo.setTitle(newTitle, mFolder.mLauncherDelegate.getModelWriter());
|
||||
onTitleChanged(mInfo.title);
|
||||
mFolder.mFolderName.setText(mInfo.title);
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -49,6 +48,7 @@ import com.android.launcher3.pageindicators.PageIndicatorDots;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
@@ -102,7 +102,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
|
||||
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||
|
||||
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
|
||||
mViewCache = BaseActivity.fromContext(context).getViewCache();
|
||||
mViewCache = ActivityContext.lookupContext(context).getViewCache();
|
||||
}
|
||||
|
||||
public void setFolder(Folder folder) {
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||
import com.android.launcher3.model.ModelWriter;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.views.BaseDragLayer.LayoutParams;
|
||||
import com.android.launcher3.widget.LocalColorExtractor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Wrapper around Launcher methods to allow folders in non-launcher context
|
||||
*/
|
||||
public class LauncherDelegate {
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final Rect mTempRect = new Rect();
|
||||
private final RectF mTempRectF = new RectF();
|
||||
|
||||
private LauncherDelegate(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
}
|
||||
|
||||
void init(Folder folder, FolderIcon icon) {
|
||||
folder.setDragController(mLauncher.getDragController());
|
||||
icon.setOnFocusChangeListener(mLauncher.getFocusHandler());
|
||||
}
|
||||
|
||||
boolean isDraggingEnabled() {
|
||||
return mLauncher.isDraggingEnabled();
|
||||
}
|
||||
|
||||
void beginDragShared(View child, DragSource source, DragOptions options) {
|
||||
mLauncher.getWorkspace().beginDragShared(child, source, options);
|
||||
}
|
||||
|
||||
ModelWriter getModelWriter() {
|
||||
return mLauncher.getModelWriter();
|
||||
}
|
||||
|
||||
void forEachVisibleWorkspacePage(Consumer<View> callback) {
|
||||
mLauncher.getWorkspace().forEachVisiblePage(callback);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Launcher getLauncher() {
|
||||
return mLauncher;
|
||||
}
|
||||
|
||||
void addRectForColorExtraction(BaseDragLayer.LayoutParams lp, LocalColorExtractor target) {
|
||||
mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
|
||||
target.getExtractedRectForViewRect(mLauncher,
|
||||
mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
|
||||
if (!mTempRectF.isEmpty()) {
|
||||
target.addLocation(Arrays.asList(mTempRectF));
|
||||
}
|
||||
}
|
||||
|
||||
void replaceFolderWithFinalItem(Folder folder) {
|
||||
// Add the last remaining child to the workspace in place of the folder
|
||||
Runnable onCompleteRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int itemCount = folder.getItemCount();
|
||||
FolderInfo info = folder.mInfo;
|
||||
if (itemCount <= 1) {
|
||||
View newIcon = null;
|
||||
WorkspaceItemInfo finalItem = null;
|
||||
|
||||
if (itemCount == 1) {
|
||||
// Move the item from the folder to the workspace, in the position of the
|
||||
// folder
|
||||
CellLayout cellLayout = mLauncher.getCellLayout(info.container,
|
||||
info.screenId);
|
||||
finalItem = info.contents.remove(0);
|
||||
newIcon = mLauncher.createShortcut(cellLayout, finalItem);
|
||||
mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
|
||||
info.container, info.screenId, info.cellX, info.cellY);
|
||||
}
|
||||
|
||||
// Remove the folder
|
||||
mLauncher.removeItem(folder.mFolderIcon, info, true /* deleteFromDb */);
|
||||
if (folder.mFolderIcon instanceof DropTarget) {
|
||||
folder.mDragController.removeDropTarget((DropTarget) folder.mFolderIcon);
|
||||
}
|
||||
|
||||
if (newIcon != null) {
|
||||
// We add the child after removing the folder to prevent both from existing
|
||||
// at the same time in the CellLayout. We need to add the new item with
|
||||
// addInScreenFromBind() to ensure that hotseat items are placed correctly.
|
||||
mLauncher.getWorkspace().addInScreenFromBind(newIcon, info);
|
||||
|
||||
// Focus the newly created child
|
||||
newIcon.requestFocus();
|
||||
}
|
||||
if (finalItem != null) {
|
||||
StatsLogger logger = mLauncher.getStatsLogManager().logger()
|
||||
.withItemInfo(finalItem);
|
||||
((Optional<InstanceId>) folder.mDragController.getLogInstanceId())
|
||||
.map(logger::withInstanceId)
|
||||
.orElse(logger)
|
||||
.log(LAUNCHER_FOLDER_CONVERTED_TO_ICON);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
View finalChild = folder.mContent.getLastItem();
|
||||
if (finalChild != null) {
|
||||
folder.mFolderIcon.performDestroyAnimation(onCompleteRunnable);
|
||||
} else {
|
||||
onCompleteRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean interceptOutsideTouch(MotionEvent ev, BaseDragLayer dl, Folder folder) {
|
||||
if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
|
||||
// Do not close the container if in drag and drop.
|
||||
if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// TODO: add ww log if need to gather tap outside to close folder
|
||||
folder.close(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class FallbackDelegate extends LauncherDelegate {
|
||||
|
||||
private final ActivityContext mContext;
|
||||
private ModelWriter mWriter;
|
||||
|
||||
FallbackDelegate(ActivityContext context) {
|
||||
super(null);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
void init(Folder folder, FolderIcon icon) {
|
||||
folder.setDragController(mContext.getDragController());
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isDraggingEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
void beginDragShared(View child, DragSource source, DragOptions options) { }
|
||||
|
||||
@Override
|
||||
ModelWriter getModelWriter() {
|
||||
if (mWriter == null) {
|
||||
mWriter = LauncherAppState.getInstance((Context) mContext).getModel()
|
||||
.getWriter(false, false);
|
||||
}
|
||||
return mWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
void forEachVisibleWorkspacePage(Consumer<View> callback) { }
|
||||
|
||||
@Override
|
||||
Launcher getLauncher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void replaceFolderWithFinalItem(Folder folder) { }
|
||||
|
||||
@Override
|
||||
boolean interceptOutsideTouch(MotionEvent ev, BaseDragLayer dl, Folder folder) {
|
||||
folder.close(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
void addRectForColorExtraction(LayoutParams lp, LocalColorExtractor target) { }
|
||||
}
|
||||
|
||||
static LauncherDelegate from(ActivityContext context) {
|
||||
return context instanceof Launcher
|
||||
? new LauncherDelegate((Launcher) context)
|
||||
: new FallbackDelegate(context);
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,12 @@ import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
/**
|
||||
* Utility class for offloading some class from UI thread
|
||||
@@ -43,21 +44,21 @@ public class UiThreadHelper {
|
||||
private static final int MSG_RUN_COMMAND = 3;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static void hideKeyboardAsync(Launcher launcher, IBinder token) {
|
||||
public static void hideKeyboardAsync(ActivityContext activityContext, IBinder token) {
|
||||
View root = activityContext.getDragLayer();
|
||||
if (Utilities.ATLEAST_R) {
|
||||
WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets();
|
||||
WindowInsets rootInsets = root.getRootWindowInsets();
|
||||
boolean isImeShown = rootInsets != null && rootInsets.isVisible(
|
||||
WindowInsets.Type.ime());
|
||||
if (isImeShown) {
|
||||
// this call is already asynchronous
|
||||
launcher.getAppsView().getWindowInsetsController().hide(
|
||||
WindowInsets.Type.ime()
|
||||
);
|
||||
root.getWindowInsetsController().hide(WindowInsets.Type.ime());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget();
|
||||
Message.obtain(HANDLER.get(root.getContext()),
|
||||
MSG_HIDE_KEYBOARD, token).sendToTarget();
|
||||
}
|
||||
|
||||
public static void setOrientationAsync(Activity activity, int orientation) {
|
||||
|
||||
@@ -23,7 +23,9 @@ import android.view.View.AccessibilityDelegate;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.dot.DotInfo;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
|
||||
/**
|
||||
* An interface to be used along with a context for various activities in Launcher. This allows a
|
||||
@@ -86,6 +88,17 @@ public interface ActivityContext {
|
||||
|
||||
DeviceProfile getDeviceProfile();
|
||||
|
||||
default ViewCache getViewCache() {
|
||||
return new ViewCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller for supporting item drag-and-drop
|
||||
*/
|
||||
default <T extends DragController> T getDragController() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ActivityContext associated with the given Context.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user