2013-06-05 22:57:57 -04:00
|
|
|
package com.android.launcher3;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2018-09-18 16:17:22 -07:00
|
|
|
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
|
|
|
|
|
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
|
2021-02-03 22:02:43 +00:00
|
|
|
import static com.android.launcher3.Utilities.ATLEAST_S;
|
2018-09-18 16:17:22 -07:00
|
|
|
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
|
|
|
|
|
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;
|
|
|
|
|
|
2011-02-18 19:25:06 -08:00
|
|
|
import android.animation.AnimatorSet;
|
|
|
|
|
import android.animation.ObjectAnimator;
|
|
|
|
|
import android.animation.PropertyValuesHolder;
|
2011-11-08 15:07:01 -08:00
|
|
|
import android.appwidget.AppWidgetHostView;
|
2011-02-18 19:25:06 -08:00
|
|
|
import android.appwidget.AppWidgetProviderInfo;
|
|
|
|
|
import android.content.Context;
|
2015-08-20 12:33:21 -07:00
|
|
|
import android.graphics.Point;
|
2011-11-08 15:07:01 -08:00
|
|
|
import android.graphics.Rect;
|
2021-02-03 22:02:43 +00:00
|
|
|
import android.os.Bundle;
|
2016-09-13 21:07:31 -07:00
|
|
|
import android.util.AttributeSet;
|
2021-03-02 13:35:36 +00:00
|
|
|
import android.util.SizeF;
|
2016-02-10 16:18:15 -08:00
|
|
|
import android.view.KeyEvent;
|
2016-09-23 11:01:10 -07:00
|
|
|
import android.view.MotionEvent;
|
2016-02-10 16:18:15 -08:00
|
|
|
import android.view.View;
|
2017-09-28 13:43:24 -07:00
|
|
|
import android.view.ViewGroup;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2021-02-03 22:02:43 +00:00
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
|
|
2015-09-24 11:23:31 -07:00
|
|
|
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
2016-09-13 21:07:31 -07:00
|
|
|
import com.android.launcher3.dragndrop.DragLayer;
|
2019-12-09 14:55:56 -08:00
|
|
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
2017-12-18 13:49:44 -08:00
|
|
|
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
2021-02-22 14:03:44 +00:00
|
|
|
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
2015-09-24 11:23:31 -07:00
|
|
|
|
2019-04-03 14:05:08 -07:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
2017-09-28 13:43:24 -07:00
|
|
|
public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
|
2015-05-18 20:52:57 -07:00
|
|
|
private static final int SNAP_DURATION = 150;
|
|
|
|
|
private static final float DIMMED_HANDLE_ALPHA = 0f;
|
|
|
|
|
private static final float RESIZE_THRESHOLD = 0.66f;
|
|
|
|
|
|
2015-08-20 12:33:21 -07:00
|
|
|
private static final Rect sTmpRect = new Rect();
|
|
|
|
|
|
|
|
|
|
// Represents the cell size on the grid in the two orientations.
|
2020-11-01 13:06:43 -08:00
|
|
|
public static final MainThreadInitializedObject<Point[]> CELL_SIZE =
|
2019-12-09 14:55:56 -08:00
|
|
|
new MainThreadInitializedObject<>(c -> {
|
|
|
|
|
InvariantDeviceProfile inv = LauncherAppState.getIDP(c);
|
|
|
|
|
return new Point[] {inv.landscapeProfile.getCellSize(),
|
|
|
|
|
inv.portraitProfile.getCellSize()};
|
|
|
|
|
});
|
2015-05-18 20:52:57 -07:00
|
|
|
|
2021-02-25 10:45:20 -05:00
|
|
|
// Represents the border spacing size on the grid in the two orientations.
|
|
|
|
|
public static final MainThreadInitializedObject<int[]> BORDER_SPACING_SIZE =
|
|
|
|
|
new MainThreadInitializedObject<>(c -> {
|
|
|
|
|
InvariantDeviceProfile inv = LauncherAppState.getIDP(c);
|
|
|
|
|
return new int[] {inv.landscapeProfile.cellLayoutBorderSpacingPx,
|
|
|
|
|
inv.portraitProfile.cellLayoutBorderSpacingPx};
|
|
|
|
|
});
|
|
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
private static final int HANDLE_COUNT = 4;
|
|
|
|
|
private static final int INDEX_LEFT = 0;
|
|
|
|
|
private static final int INDEX_TOP = 1;
|
|
|
|
|
private static final int INDEX_RIGHT = 2;
|
|
|
|
|
private static final int INDEX_BOTTOM = 3;
|
|
|
|
|
|
2015-05-18 20:52:57 -07:00
|
|
|
private final Launcher mLauncher;
|
2016-09-13 21:07:31 -07:00
|
|
|
private final DragViewStateAnnouncer mStateAnnouncer;
|
2018-08-13 16:10:14 -07:00
|
|
|
private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
|
2016-09-13 21:07:31 -07:00
|
|
|
|
|
|
|
|
private final View[] mDragHandles = new View[HANDLE_COUNT];
|
2019-04-03 14:05:08 -07:00
|
|
|
private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
|
2015-05-18 20:52:57 -07:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
private LauncherAppWidgetHostView mWidgetView;
|
|
|
|
|
private CellLayout mCellLayout;
|
|
|
|
|
private DragLayer mDragLayer;
|
2015-05-18 20:52:57 -07:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
private Rect mWidgetPadding;
|
2015-05-18 20:52:57 -07:00
|
|
|
|
|
|
|
|
private final int mBackgroundPadding;
|
|
|
|
|
private final int mTouchTargetWidth;
|
|
|
|
|
|
|
|
|
|
private final int[] mDirectionVector = new int[2];
|
|
|
|
|
private final int[] mLastDirectionVector = new int[2];
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
private final IntRange mTempRange1 = new IntRange();
|
|
|
|
|
private final IntRange mTempRange2 = new IntRange();
|
|
|
|
|
|
|
|
|
|
private final IntRange mDeltaXRange = new IntRange();
|
|
|
|
|
private final IntRange mBaselineX = new IntRange();
|
|
|
|
|
|
|
|
|
|
private final IntRange mDeltaYRange = new IntRange();
|
|
|
|
|
private final IntRange mBaselineY = new IntRange();
|
2015-09-24 11:23:31 -07:00
|
|
|
|
2011-02-18 19:25:06 -08:00
|
|
|
private boolean mLeftBorderActive;
|
|
|
|
|
private boolean mRightBorderActive;
|
|
|
|
|
private boolean mTopBorderActive;
|
|
|
|
|
private boolean mBottomBorderActive;
|
|
|
|
|
|
|
|
|
|
private int mResizeMode;
|
2011-03-02 19:03:11 -08:00
|
|
|
|
2011-02-18 19:25:06 -08:00
|
|
|
private int mRunningHInc;
|
|
|
|
|
private int mRunningVInc;
|
|
|
|
|
private int mMinHSpan;
|
|
|
|
|
private int mMinVSpan;
|
|
|
|
|
private int mDeltaX;
|
|
|
|
|
private int mDeltaY;
|
2012-04-11 18:06:28 -07:00
|
|
|
private int mDeltaXAddOn;
|
|
|
|
|
private int mDeltaYAddOn;
|
2011-03-03 17:26:50 -08:00
|
|
|
|
2012-07-13 15:59:15 -07:00
|
|
|
private int mTopTouchRegionAdjustment = 0;
|
|
|
|
|
private int mBottomTouchRegionAdjustment = 0;
|
|
|
|
|
|
2016-09-23 11:01:10 -07:00
|
|
|
private int mXDown, mYDown;
|
|
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
public AppWidgetResizeFrame(Context context) {
|
|
|
|
|
this(context, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AppWidgetResizeFrame(Context context, AttributeSet attrs) {
|
|
|
|
|
this(context, attrs, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AppWidgetResizeFrame(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
super(context, attrs, defStyleAttr);
|
|
|
|
|
|
|
|
|
|
mLauncher = Launcher.getLauncher(context);
|
|
|
|
|
mStateAnnouncer = DragViewStateAnnouncer.createFor(this);
|
|
|
|
|
|
|
|
|
|
mBackgroundPadding = getResources()
|
|
|
|
|
.getDimensionPixelSize(R.dimen.resize_frame_background_padding);
|
|
|
|
|
mTouchTargetWidth = 2 * mBackgroundPadding;
|
2018-08-13 16:10:14 -07:00
|
|
|
mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
|
2019-04-03 14:05:08 -07:00
|
|
|
|
|
|
|
|
for (int i = 0; i < HANDLE_COUNT; i++) {
|
|
|
|
|
mSystemGestureExclusionRects.add(new Rect());
|
|
|
|
|
}
|
2016-09-13 21:07:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onFinishInflate() {
|
|
|
|
|
super.onFinishInflate();
|
|
|
|
|
|
2017-09-28 13:43:24 -07:00
|
|
|
ViewGroup content = (ViewGroup) getChildAt(0);
|
2016-09-13 21:07:31 -07:00
|
|
|
for (int i = 0; i < HANDLE_COUNT; i ++) {
|
2017-09-28 13:43:24 -07:00
|
|
|
mDragHandles[i] = content.getChildAt(i);
|
2016-09-13 21:07:31 -07:00
|
|
|
}
|
|
|
|
|
}
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2019-04-03 14:05:08 -07:00
|
|
|
@Override
|
|
|
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
|
|
|
super.onLayout(changed, l, t, r, b);
|
|
|
|
|
if (Utilities.ATLEAST_Q) {
|
|
|
|
|
for (int i = 0; i < HANDLE_COUNT; i++) {
|
|
|
|
|
View dragHandle = mDragHandles[i];
|
|
|
|
|
mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
|
|
|
|
|
dragHandle.getRight(), dragHandle.getBottom());
|
|
|
|
|
}
|
|
|
|
|
setSystemGestureExclusionRects(mSystemGestureExclusionRects);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-28 13:43:24 -07:00
|
|
|
public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
|
|
|
|
|
Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
|
|
|
|
|
AbstractFloatingView.closeAllOpenViews(launcher);
|
|
|
|
|
|
|
|
|
|
DragLayer dl = launcher.getDragLayer();
|
|
|
|
|
AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
|
|
|
|
|
.inflate(R.layout.app_widget_resize_frame, dl, false);
|
|
|
|
|
frame.setupForWidget(widget, cellLayout, dl);
|
|
|
|
|
((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
|
|
|
|
|
|
|
|
|
|
dl.addView(frame);
|
|
|
|
|
frame.mIsOpen = true;
|
|
|
|
|
frame.snapToWidget(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
|
2016-09-13 21:07:31 -07:00
|
|
|
DragLayer dragLayer) {
|
2011-02-18 19:25:06 -08:00
|
|
|
mCellLayout = cellLayout;
|
|
|
|
|
mWidgetView = widgetView;
|
2014-03-05 18:07:04 -08:00
|
|
|
LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
|
|
|
|
|
widgetView.getAppWidgetInfo();
|
|
|
|
|
mResizeMode = info.resizeMode;
|
2011-03-11 15:29:03 -08:00
|
|
|
mDragLayer = dragLayer;
|
2011-03-02 19:03:11 -08:00
|
|
|
|
2015-08-03 13:05:01 -07:00
|
|
|
mMinHSpan = info.minSpanX;
|
|
|
|
|
mMinVSpan = info.minSpanY;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2017-08-16 04:59:08 -07:00
|
|
|
mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(),
|
|
|
|
|
widgetView.getAppWidgetInfo().provider, null);
|
2014-03-05 18:07:04 -08:00
|
|
|
|
2011-02-18 19:25:06 -08:00
|
|
|
if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDragHandles[INDEX_TOP].setVisibility(GONE);
|
|
|
|
|
mDragHandles[INDEX_BOTTOM].setVisibility(GONE);
|
2011-02-18 19:25:06 -08:00
|
|
|
} else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDragHandles[INDEX_LEFT].setVisibility(GONE);
|
|
|
|
|
mDragHandles[INDEX_RIGHT].setVisibility(GONE);
|
2011-03-02 19:03:11 -08:00
|
|
|
}
|
|
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
// When we create the resize frame, we first mark all cells as unoccupied. The appropriate
|
|
|
|
|
// cells (same if not resized, or different) will be marked as occupied when the resize
|
|
|
|
|
// frame is dismissed.
|
|
|
|
|
mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
|
2016-02-10 16:18:15 -08:00
|
|
|
|
|
|
|
|
setOnKeyListener(this);
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean beginResizeIfPointInRegion(int x, int y) {
|
|
|
|
|
boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
|
|
|
|
|
boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
|
2012-07-13 15:59:15 -07:00
|
|
|
|
2011-03-02 19:03:11 -08:00
|
|
|
mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
|
|
|
|
|
mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
|
2012-07-13 15:59:15 -07:00
|
|
|
mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
|
|
|
|
|
mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
|
|
|
|
|
&& verticalActive;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
|
|
|
|
boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
|
|
|
|
|
|| mTopBorderActive || mBottomBorderActive;
|
|
|
|
|
|
|
|
|
|
if (anyBordersActive) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDragHandles[INDEX_LEFT].setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
|
|
|
|
|
mDragHandles[INDEX_RIGHT].setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
|
|
|
|
|
mDragHandles[INDEX_TOP].setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
|
|
|
|
|
mDragHandles[INDEX_BOTTOM].setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mLeftBorderActive) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaXRange.set(-getLeft(), getWidth() - 2 * mTouchTargetWidth);
|
2011-02-18 19:25:06 -08:00
|
|
|
} else if (mRightBorderActive) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaXRange.set(2 * mTouchTargetWidth - getWidth(), mDragLayer.getWidth() - getRight());
|
|
|
|
|
} else {
|
|
|
|
|
mDeltaXRange.set(0, 0);
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
2016-09-13 21:07:31 -07:00
|
|
|
mBaselineX.set(getLeft(), getRight());
|
2011-02-18 19:25:06 -08:00
|
|
|
|
|
|
|
|
if (mTopBorderActive) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaYRange.set(-getTop(), getHeight() - 2 * mTouchTargetWidth);
|
2011-02-18 19:25:06 -08:00
|
|
|
} else if (mBottomBorderActive) {
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaYRange.set(2 * mTouchTargetWidth - getHeight(), mDragLayer.getHeight() - getBottom());
|
|
|
|
|
} else {
|
|
|
|
|
mDeltaYRange.set(0, 0);
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
2016-09-13 21:07:31 -07:00
|
|
|
mBaselineY.set(getTop(), getBottom());
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
return anyBordersActive;
|
2012-04-11 18:06:28 -07:00
|
|
|
}
|
|
|
|
|
|
2011-03-03 17:26:50 -08:00
|
|
|
/**
|
2016-09-13 21:07:31 -07:00
|
|
|
* Based on the deltas, we resize the frame.
|
2011-03-03 17:26:50 -08:00
|
|
|
*/
|
2016-09-13 21:07:31 -07:00
|
|
|
public void visualizeResizeForDelta(int deltaX, int deltaY) {
|
|
|
|
|
mDeltaX = mDeltaXRange.clamp(deltaX);
|
|
|
|
|
mDeltaY = mDeltaYRange.clamp(deltaY);
|
|
|
|
|
|
2011-03-11 15:29:03 -08:00
|
|
|
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaX = mDeltaXRange.clamp(deltaX);
|
|
|
|
|
mBaselineX.applyDelta(mLeftBorderActive, mRightBorderActive, mDeltaX, mTempRange1);
|
|
|
|
|
lp.x = mTempRange1.start;
|
|
|
|
|
lp.width = mTempRange1.size();
|
2011-03-11 15:29:03 -08:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
mDeltaY = mDeltaYRange.clamp(deltaY);
|
|
|
|
|
mBaselineY.applyDelta(mTopBorderActive, mBottomBorderActive, mDeltaY, mTempRange1);
|
|
|
|
|
lp.y = mTempRange1.start;
|
|
|
|
|
lp.height = mTempRange1.size();
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
resizeWidgetIfNeeded(false);
|
2016-12-28 10:49:55 -08:00
|
|
|
|
|
|
|
|
// When the widget resizes in multi-window mode, the translation value changes to maintain
|
|
|
|
|
// a center fit. These overrides ensure the resize frame always aligns with the widget view.
|
|
|
|
|
getSnappedRectRelativeToDragLayer(sTmpRect);
|
|
|
|
|
if (mLeftBorderActive) {
|
|
|
|
|
lp.width = sTmpRect.width() + sTmpRect.left - lp.x;
|
|
|
|
|
}
|
|
|
|
|
if (mTopBorderActive) {
|
|
|
|
|
lp.height = sTmpRect.height() + sTmpRect.top - lp.y;
|
|
|
|
|
}
|
|
|
|
|
if (mRightBorderActive) {
|
|
|
|
|
lp.x = sTmpRect.left;
|
|
|
|
|
}
|
|
|
|
|
if (mBottomBorderActive) {
|
|
|
|
|
lp.y = sTmpRect.top;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-18 19:25:06 -08:00
|
|
|
requestLayout();
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
private static int getSpanIncrement(float deltaFrac) {
|
|
|
|
|
return Math.abs(deltaFrac) > RESIZE_THRESHOLD ? Math.round(deltaFrac) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-03 17:26:50 -08:00
|
|
|
/**
|
|
|
|
|
* Based on the current deltas, we determine if and how to resize the widget.
|
|
|
|
|
*/
|
2012-04-11 18:06:28 -07:00
|
|
|
private void resizeWidgetIfNeeded(boolean onDismiss) {
|
2021-02-09 11:05:00 -05:00
|
|
|
DeviceProfile dp = mLauncher.getDeviceProfile();
|
|
|
|
|
float xThreshold = mCellLayout.getCellWidth() + dp.cellLayoutBorderSpacingPx;
|
|
|
|
|
float yThreshold = mCellLayout.getCellHeight() + dp.cellLayoutBorderSpacingPx;
|
2012-04-11 18:06:28 -07:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
int hSpanInc = getSpanIncrement((mDeltaX + mDeltaXAddOn) / xThreshold - mRunningHInc);
|
|
|
|
|
int vSpanInc = getSpanIncrement((mDeltaY + mDeltaYAddOn) / yThreshold - mRunningVInc);
|
2011-03-08 18:35:52 -08:00
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
mDirectionVector[0] = 0;
|
|
|
|
|
mDirectionVector[1] = 0;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
|
|
|
|
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
|
2011-03-03 17:26:50 -08:00
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
int spanX = lp.cellHSpan;
|
|
|
|
|
int spanY = lp.cellVSpan;
|
|
|
|
|
int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
|
|
|
|
|
int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
|
|
|
|
|
|
2011-03-03 17:26:50 -08:00
|
|
|
// For each border, we bound the resizing based on the minimum width, and the maximum
|
|
|
|
|
// expandability.
|
2016-09-13 21:07:31 -07:00
|
|
|
mTempRange1.set(cellX, spanX + cellX);
|
|
|
|
|
int hSpanDelta = mTempRange1.applyDeltaAndBound(mLeftBorderActive, mRightBorderActive,
|
|
|
|
|
hSpanInc, mMinHSpan, mCellLayout.getCountX(), mTempRange2);
|
|
|
|
|
cellX = mTempRange2.start;
|
|
|
|
|
spanX = mTempRange2.size();
|
|
|
|
|
if (hSpanDelta != 0) {
|
|
|
|
|
mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
mTempRange1.set(cellY, spanY + cellY);
|
|
|
|
|
int vSpanDelta = mTempRange1.applyDeltaAndBound(mTopBorderActive, mBottomBorderActive,
|
|
|
|
|
vSpanInc, mMinVSpan, mCellLayout.getCountY(), mTempRange2);
|
|
|
|
|
cellY = mTempRange2.start;
|
|
|
|
|
spanY = mTempRange2.size();
|
|
|
|
|
if (vSpanDelta != 0) {
|
|
|
|
|
mDirectionVector[1] = mTopBorderActive ? -1 : 1;
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
|
|
|
|
|
|
2012-08-27 15:18:53 -07:00
|
|
|
// We always want the final commit to match the feedback, so we make sure to use the
|
|
|
|
|
// last used direction vector when committing the resize / reorder.
|
|
|
|
|
if (onDismiss) {
|
|
|
|
|
mDirectionVector[0] = mLastDirectionVector[0];
|
|
|
|
|
mDirectionVector[1] = mLastDirectionVector[1];
|
|
|
|
|
} else {
|
|
|
|
|
mLastDirectionVector[0] = mDirectionVector[0];
|
|
|
|
|
mLastDirectionVector[1] = mDirectionVector[1];
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
|
|
|
|
|
mDirectionVector, onDismiss)) {
|
2015-09-24 11:23:31 -07:00
|
|
|
if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) {
|
|
|
|
|
mStateAnnouncer.announce(
|
|
|
|
|
mLauncher.getString(R.string.widget_resized, spanX, spanY));
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-11 18:06:28 -07:00
|
|
|
lp.tmpCellX = cellX;
|
|
|
|
|
lp.tmpCellY = cellY;
|
|
|
|
|
lp.cellHSpan = spanX;
|
|
|
|
|
lp.cellVSpan = spanY;
|
|
|
|
|
mRunningVInc += vSpanDelta;
|
|
|
|
|
mRunningHInc += hSpanDelta;
|
2015-09-24 11:23:31 -07:00
|
|
|
|
2012-04-27 18:12:05 -07:00
|
|
|
if (!onDismiss) {
|
|
|
|
|
updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
|
|
|
|
|
}
|
2012-04-11 18:06:28 -07:00
|
|
|
}
|
2011-03-11 15:29:03 -08:00
|
|
|
mWidgetView.requestLayout();
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
2020-04-06 15:11:17 -07:00
|
|
|
public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
|
2021-02-03 22:02:43 +00:00
|
|
|
int spanX, int spanY) {
|
2021-03-02 13:35:36 +00:00
|
|
|
List<SizeF> sizes = getWidgetSizes(launcher, spanX, spanY);
|
2021-02-03 22:02:43 +00:00
|
|
|
if (ATLEAST_S) {
|
|
|
|
|
widgetView.updateAppWidgetSize(new Bundle(), sizes);
|
|
|
|
|
} else {
|
|
|
|
|
Rect bounds = getMinMaxSizes(sizes, null /* outRect */);
|
|
|
|
|
widgetView.updateAppWidgetSize(new Bundle(), bounds.left, bounds.top, bounds.right,
|
|
|
|
|
bounds.bottom);
|
|
|
|
|
}
|
2012-09-10 15:53:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-02 13:35:36 +00:00
|
|
|
private static SizeF getWidgetSize(Context context, Point cellSize, int spanX, int spanY,
|
2021-02-25 10:45:20 -05:00
|
|
|
int borderSpacing) {
|
2016-03-10 05:34:30 -08:00
|
|
|
final float density = context.getResources().getDisplayMetrics().density;
|
2021-02-25 10:45:20 -05:00
|
|
|
final float hBorderSpacing = (spanX - 1) * borderSpacing;
|
|
|
|
|
final float vBorderSpacing = (spanY - 1) * borderSpacing;
|
|
|
|
|
|
2021-03-02 13:35:36 +00:00
|
|
|
return new SizeF(((spanX * cellSize.x) + hBorderSpacing) / density,
|
|
|
|
|
((spanY * cellSize.y) + vBorderSpacing) / density);
|
2021-02-03 22:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns the list of sizes for a widget of given span, in dp. */
|
2021-03-02 13:35:36 +00:00
|
|
|
public static ArrayList<SizeF> getWidgetSizes(Context context, int spanX, int spanY) {
|
2019-12-09 14:55:56 -08:00
|
|
|
final Point[] cellSize = CELL_SIZE.get(context);
|
2021-02-25 10:45:20 -05:00
|
|
|
final int[] borderSpacing = BORDER_SPACING_SIZE.get(context);
|
2012-04-27 18:12:05 -07:00
|
|
|
|
2021-03-02 13:35:36 +00:00
|
|
|
SizeF landSize = getWidgetSize(context, cellSize[0], spanX, spanY, borderSpacing[0]);
|
|
|
|
|
SizeF portSize = getWidgetSize(context, cellSize[1], spanX, spanY, borderSpacing[1]);
|
2021-02-03 22:02:43 +00:00
|
|
|
|
2021-03-02 13:35:36 +00:00
|
|
|
ArrayList<SizeF> sizes = new ArrayList<>(2);
|
2021-02-03 22:02:43 +00:00
|
|
|
sizes.add(landSize);
|
|
|
|
|
sizes.add(portSize);
|
|
|
|
|
return sizes;
|
|
|
|
|
}
|
2021-02-09 11:05:00 -05:00
|
|
|
|
2021-02-03 22:02:43 +00:00
|
|
|
/**
|
|
|
|
|
* Returns the min and max widths and heights given a list of sizes, in dp.
|
|
|
|
|
*
|
|
|
|
|
* @param sizes List of sizes to get the min/max from.
|
|
|
|
|
* @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If
|
|
|
|
|
* null, a new rectangle will be allocated.
|
|
|
|
|
* @return A rectangle with the left (resp. top) is used for the min width (resp. height) and
|
|
|
|
|
* the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is
|
|
|
|
|
* empty.
|
|
|
|
|
*/
|
2021-03-02 13:35:36 +00:00
|
|
|
public static Rect getMinMaxSizes(List<SizeF> sizes, @Nullable Rect outRect) {
|
2021-02-03 22:02:43 +00:00
|
|
|
if (outRect == null) {
|
|
|
|
|
outRect = new Rect();
|
|
|
|
|
}
|
|
|
|
|
if (sizes.isEmpty()) {
|
|
|
|
|
outRect.set(0, 0, 0, 0);
|
|
|
|
|
} else {
|
2021-03-02 13:35:36 +00:00
|
|
|
SizeF first = sizes.get(0);
|
|
|
|
|
outRect.set((int) first.getWidth(), (int) first.getHeight(), (int) first.getWidth(),
|
|
|
|
|
(int) first.getHeight());
|
2021-02-03 22:02:43 +00:00
|
|
|
for (int i = 1; i < sizes.size(); i++) {
|
2021-03-02 13:35:36 +00:00
|
|
|
outRect.union((int) sizes.get(i).getWidth(), (int) sizes.get(i).getHeight());
|
2021-02-03 22:02:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return outRect;
|
|
|
|
|
}
|
2012-04-27 18:12:05 -07:00
|
|
|
|
2021-02-03 22:02:43 +00:00
|
|
|
/**
|
|
|
|
|
* Returns the range of sizes a widget may be displayed, given its span.
|
|
|
|
|
*
|
|
|
|
|
* @param context Context in which the View is rendered.
|
|
|
|
|
* @param spanX Width of the widget, in cells.
|
|
|
|
|
* @param spanY Height of the widget, in cells.
|
|
|
|
|
* @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If
|
|
|
|
|
* null, a new rectangle will be allocated.
|
|
|
|
|
*/
|
|
|
|
|
public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY,
|
|
|
|
|
@Nullable Rect outRect) {
|
|
|
|
|
return getMinMaxSizes(getWidgetSizes(context, spanX, spanY), outRect);
|
2012-04-27 18:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-18 02:05:01 -07:00
|
|
|
@Override
|
|
|
|
|
protected void onDetachedFromWindow() {
|
|
|
|
|
super.onDetachedFromWindow();
|
|
|
|
|
|
|
|
|
|
// We are done with resizing the widget. Save the widget size & position to LauncherModel
|
2012-04-11 18:06:28 -07:00
|
|
|
resizeWidgetIfNeeded(true);
|
|
|
|
|
}
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2016-09-23 11:01:10 -07:00
|
|
|
private void onTouchUp() {
|
2021-02-09 11:05:00 -05:00
|
|
|
DeviceProfile dp = mLauncher.getDeviceProfile();
|
|
|
|
|
int xThreshold = mCellLayout.getCellWidth() + dp.cellLayoutBorderSpacingPx;
|
|
|
|
|
int yThreshold = mCellLayout.getCellHeight() + dp.cellLayoutBorderSpacingPx;
|
2012-04-11 18:06:28 -07:00
|
|
|
|
2016-12-28 10:49:55 -08:00
|
|
|
mDeltaXAddOn = mRunningHInc * xThreshold;
|
|
|
|
|
mDeltaYAddOn = mRunningVInc * yThreshold;
|
2012-04-11 18:06:28 -07:00
|
|
|
mDeltaX = 0;
|
|
|
|
|
mDeltaY = 0;
|
2011-02-18 19:25:06 -08:00
|
|
|
|
2018-08-13 16:10:14 -07:00
|
|
|
post(() -> snapToWidget(true));
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-28 10:49:55 -08:00
|
|
|
/**
|
|
|
|
|
* Returns the rect of this view when the frame is snapped around the widget, with the bounds
|
|
|
|
|
* relative to the {@link DragLayer}.
|
|
|
|
|
*/
|
|
|
|
|
private void getSnappedRectRelativeToDragLayer(Rect out) {
|
2016-12-19 14:12:05 -08:00
|
|
|
float scale = mWidgetView.getScaleToFit();
|
2016-12-12 15:43:18 -08:00
|
|
|
|
2016-12-28 10:49:55 -08:00
|
|
|
mDragLayer.getViewRectRelativeToSelf(mWidgetView, out);
|
|
|
|
|
|
|
|
|
|
int width = 2 * mBackgroundPadding
|
|
|
|
|
+ (int) (scale * (out.width() - mWidgetPadding.left - mWidgetPadding.right));
|
|
|
|
|
int height = 2 * mBackgroundPadding
|
|
|
|
|
+ (int) (scale * (out.height() - mWidgetPadding.top - mWidgetPadding.bottom));
|
2011-06-13 17:13:42 -07:00
|
|
|
|
2016-12-28 10:49:55 -08:00
|
|
|
int x = (int) (out.left - mBackgroundPadding + scale * mWidgetPadding.left);
|
|
|
|
|
int y = (int) (out.top - mBackgroundPadding + scale * mWidgetPadding.top);
|
2013-07-09 15:32:37 -07:00
|
|
|
|
2016-12-28 10:49:55 -08:00
|
|
|
out.left = x;
|
|
|
|
|
out.top = y;
|
|
|
|
|
out.right = out.left + width;
|
|
|
|
|
out.bottom = out.top + height;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-28 13:43:24 -07:00
|
|
|
private void snapToWidget(boolean animate) {
|
2016-12-28 10:49:55 -08:00
|
|
|
getSnappedRectRelativeToDragLayer(sTmpRect);
|
|
|
|
|
int newWidth = sTmpRect.width();
|
|
|
|
|
int newHeight = sTmpRect.height();
|
|
|
|
|
int newX = sTmpRect.left;
|
|
|
|
|
int newY = sTmpRect.top;
|
2011-03-02 19:03:11 -08:00
|
|
|
|
2015-05-18 20:52:57 -07:00
|
|
|
// We need to make sure the frame's touchable regions lie fully within the bounds of the
|
2012-07-13 15:59:15 -07:00
|
|
|
// DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
|
|
|
|
|
// down accordingly to provide a proper touch target.
|
2011-03-02 19:03:11 -08:00
|
|
|
if (newY < 0) {
|
2012-07-13 15:59:15 -07:00
|
|
|
// In this case we shift the touch region down to start at the top of the DragLayer
|
|
|
|
|
mTopTouchRegionAdjustment = -newY;
|
|
|
|
|
} else {
|
|
|
|
|
mTopTouchRegionAdjustment = 0;
|
2011-03-02 19:03:11 -08:00
|
|
|
}
|
2011-03-11 15:29:03 -08:00
|
|
|
if (newY + newHeight > mDragLayer.getHeight()) {
|
2012-07-13 15:59:15 -07:00
|
|
|
// In this case we shift the touch region up to end at the bottom of the DragLayer
|
|
|
|
|
mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
|
|
|
|
|
} else {
|
|
|
|
|
mBottomTouchRegionAdjustment = 0;
|
2011-03-02 19:03:11 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-12 15:43:18 -08:00
|
|
|
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
|
2011-02-18 19:25:06 -08:00
|
|
|
if (!animate) {
|
|
|
|
|
lp.width = newWidth;
|
|
|
|
|
lp.height = newHeight;
|
|
|
|
|
lp.x = newX;
|
|
|
|
|
lp.y = newY;
|
2016-09-13 21:07:31 -07:00
|
|
|
for (int i = 0; i < HANDLE_COUNT; i++) {
|
|
|
|
|
mDragHandles[i].setAlpha(1.0f);
|
|
|
|
|
}
|
2011-02-18 19:25:06 -08:00
|
|
|
requestLayout();
|
|
|
|
|
} else {
|
2018-08-13 16:10:14 -07:00
|
|
|
ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp,
|
2018-09-18 16:17:22 -07:00
|
|
|
PropertyValuesHolder.ofInt(LAYOUT_WIDTH, lp.width, newWidth),
|
|
|
|
|
PropertyValuesHolder.ofInt(LAYOUT_HEIGHT, lp.height, newHeight),
|
|
|
|
|
PropertyValuesHolder.ofInt(LAYOUT_X, lp.x, newX),
|
|
|
|
|
PropertyValuesHolder.ofInt(LAYOUT_Y, lp.y, newY));
|
2018-08-13 16:10:14 -07:00
|
|
|
mFirstFrameAnimatorHelper.addTo(oa).addUpdateListener(a -> requestLayout());
|
2018-08-08 16:33:46 -07:00
|
|
|
|
|
|
|
|
AnimatorSet set = new AnimatorSet();
|
2016-09-13 21:07:31 -07:00
|
|
|
set.play(oa);
|
|
|
|
|
for (int i = 0; i < HANDLE_COUNT; i++) {
|
2018-08-13 16:10:14 -07:00
|
|
|
set.play(mFirstFrameAnimatorHelper.addTo(
|
|
|
|
|
ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
|
|
|
|
set.setDuration(SNAP_DURATION);
|
|
|
|
|
set.start();
|
|
|
|
|
}
|
2016-02-10 16:18:15 -08:00
|
|
|
|
|
|
|
|
setFocusableInTouchMode(true);
|
|
|
|
|
requestFocus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
|
|
// Clear the frame and give focus to the widget host view when a directional key is pressed.
|
2021-01-29 17:01:19 -08:00
|
|
|
if (shouldConsume(keyCode)) {
|
2017-09-28 13:43:24 -07:00
|
|
|
close(false);
|
2016-02-10 16:18:15 -08:00
|
|
|
mWidgetView.requestFocus();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|
2016-09-23 11:01:10 -07:00
|
|
|
|
|
|
|
|
private boolean handleTouchDown(MotionEvent ev) {
|
|
|
|
|
Rect hitRect = new Rect();
|
|
|
|
|
int x = (int) ev.getX();
|
|
|
|
|
int y = (int) ev.getY();
|
|
|
|
|
|
|
|
|
|
getHitRect(hitRect);
|
|
|
|
|
if (hitRect.contains(x, y)) {
|
|
|
|
|
if (beginResizeIfPointInRegion(x - getLeft(), y - getTop())) {
|
|
|
|
|
mXDown = x;
|
|
|
|
|
mYDown = y;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onControllerTouchEvent(MotionEvent ev) {
|
|
|
|
|
int action = ev.getAction();
|
|
|
|
|
int x = (int) ev.getX();
|
|
|
|
|
int y = (int) ev.getY();
|
|
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
|
case MotionEvent.ACTION_DOWN:
|
|
|
|
|
return handleTouchDown(ev);
|
|
|
|
|
case MotionEvent.ACTION_MOVE:
|
|
|
|
|
visualizeResizeForDelta(x - mXDown, y - mYDown);
|
|
|
|
|
break;
|
|
|
|
|
case MotionEvent.ACTION_CANCEL:
|
|
|
|
|
case MotionEvent.ACTION_UP:
|
|
|
|
|
visualizeResizeForDelta(x - mXDown, y - mYDown);
|
|
|
|
|
onTouchUp();
|
|
|
|
|
mXDown = mYDown = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
|
|
|
|
if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-09-28 13:43:24 -07:00
|
|
|
close(false);
|
2016-09-23 11:01:10 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-09-13 21:07:31 -07:00
|
|
|
|
2017-09-28 13:43:24 -07:00
|
|
|
@Override
|
|
|
|
|
protected void handleClose(boolean animate) {
|
|
|
|
|
mDragLayer.removeView(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected boolean isOfType(int type) {
|
|
|
|
|
return (type & TYPE_WIDGET_RESIZE_FRAME) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-13 21:07:31 -07:00
|
|
|
/**
|
|
|
|
|
* A mutable class for describing the range of two int values.
|
|
|
|
|
*/
|
|
|
|
|
private static class IntRange {
|
|
|
|
|
|
|
|
|
|
public int start, end;
|
|
|
|
|
|
|
|
|
|
public int clamp(int value) {
|
|
|
|
|
return Utilities.boundToRange(value, start, end);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void set(int s, int e) {
|
|
|
|
|
start = s;
|
|
|
|
|
end = e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int size() {
|
|
|
|
|
return end - start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves either the start or end edge (but never both) by {@param delta} and sets the
|
|
|
|
|
* result in {@param out}
|
|
|
|
|
*/
|
|
|
|
|
public void applyDelta(boolean moveStart, boolean moveEnd, int delta, IntRange out) {
|
|
|
|
|
out.start = moveStart ? start + delta : start;
|
|
|
|
|
out.end = moveEnd ? end + delta : end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Applies delta similar to {@link #applyDelta(boolean, boolean, int, IntRange)},
|
|
|
|
|
* with extra conditions.
|
|
|
|
|
* @param minSize minimum size after with the moving edge should not be shifted any further.
|
|
|
|
|
* For eg, if delta = -3 when moving the endEdge brings the size to less than
|
|
|
|
|
* minSize, only delta = -2 will applied
|
|
|
|
|
* @param maxEnd The maximum value to the end edge (start edge is always restricted to 0)
|
|
|
|
|
* @return the amount of increase when endEdge was moves and the amount of decrease when
|
|
|
|
|
* the start edge was moved.
|
|
|
|
|
*/
|
|
|
|
|
public int applyDeltaAndBound(boolean moveStart, boolean moveEnd, int delta,
|
|
|
|
|
int minSize, int maxEnd, IntRange out) {
|
|
|
|
|
applyDelta(moveStart, moveEnd, delta, out);
|
2017-01-03 09:30:00 -08:00
|
|
|
if (out.start < 0) {
|
2016-09-13 21:07:31 -07:00
|
|
|
out.start = 0;
|
|
|
|
|
}
|
2017-01-03 09:30:00 -08:00
|
|
|
if (out.end > maxEnd) {
|
2016-09-13 21:07:31 -07:00
|
|
|
out.end = maxEnd;
|
|
|
|
|
}
|
|
|
|
|
if (out.size() < minSize) {
|
|
|
|
|
if (moveStart) {
|
|
|
|
|
out.start = out.end - minSize;
|
|
|
|
|
} else if (moveEnd) {
|
|
|
|
|
out.end = out.start + minSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return moveEnd ? out.size() - size() : size() - out.size();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-29 17:01:19 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true only if this utility class handles the key code.
|
|
|
|
|
*/
|
|
|
|
|
public static boolean shouldConsume(int keyCode) {
|
|
|
|
|
return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
|
|
|
|
|
|| keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
|
|
|
|
|
|| keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END
|
|
|
|
|
|| keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN);
|
|
|
|
|
}
|
2011-02-18 19:25:06 -08:00
|
|
|
}
|