Decouple the scaling / translation of widget views necessary in split-screen
=> We pull apart the scale and translation that are set in a fairly static way due to split-screen vs. the general translation and scale properties that might be used more dynamically, in this case for re-order animations => This allows removal of some code that breaks reorder animations due to the accrual of translations / scales in certain edge cases. => TODO in future CL: address other translation cases and make the throw case for calling base setTranslationX/Y for Workspace Items unconditional issue 149438360 test: manual Change-Id: Ic3fde172f669e215cd25db0fcd4e1c3c873d314f
This commit is contained in:
parent
c09e8fbe9d
commit
d916206271
|
@ -29,6 +29,7 @@ import android.content.res.TypedArray;
|
|||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -70,7 +71,7 @@ import java.text.NumberFormat;
|
|||
* too aggressive.
|
||||
*/
|
||||
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
|
||||
IconLabelDotView, DraggableView {
|
||||
IconLabelDotView, DraggableView, Reorderable {
|
||||
|
||||
private static final int DISPLAY_WORKSPACE = 0;
|
||||
private static final int DISPLAY_ALL_APPS = 1;
|
||||
|
@ -78,6 +79,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
|||
|
||||
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
|
||||
|
||||
private final PointF mTranslationForReorder = new PointF(0, 0);
|
||||
private float mScaleForReorder = 1f;
|
||||
|
||||
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
|
||||
= new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
|
||||
|
@ -672,6 +675,30 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
|||
return mIconSize;
|
||||
}
|
||||
|
||||
public void setReorderOffset(float x, float y) {
|
||||
mTranslationForReorder.set(x, y);
|
||||
super.setTranslationX(x);
|
||||
super.setTranslationY(y);
|
||||
}
|
||||
|
||||
public void getReorderOffset(PointF offset) {
|
||||
offset.set(mTranslationForReorder);
|
||||
}
|
||||
|
||||
public void setReorderScale(float scale) {
|
||||
mScaleForReorder = scale;
|
||||
super.setScaleX(scale);
|
||||
super.setScaleY(scale);
|
||||
}
|
||||
|
||||
public float getReorderScale() {
|
||||
return mScaleForReorder;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return DRAGGABLE_ICON;
|
||||
|
|
|
@ -33,6 +33,7 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -54,7 +55,6 @@ import androidx.core.view.ViewCompat;
|
|||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PropertyListBuilder;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DraggableView;
|
||||
import com.android.launcher3.folder.PreviewBackground;
|
||||
|
@ -66,7 +66,6 @@ import com.android.launcher3.util.ParcelableSparseArray;
|
|||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -99,6 +98,7 @@ public class CellLayout extends ViewGroup {
|
|||
// return an (x, y) value from helper functions. Do NOT use them to maintain other state.
|
||||
@Thunk final int[] mTmpPoint = new int[2];
|
||||
@Thunk final int[] mTempLocation = new int[2];
|
||||
final PointF mTmpPointF = new PointF();
|
||||
|
||||
// Used to visualize / debug the Grid of the CellLayout
|
||||
private static final boolean VISUALIZE_GRID = false;
|
||||
|
@ -136,7 +136,7 @@ public class CellLayout extends ViewGroup {
|
|||
private final Paint mDragOutlinePaint = new Paint();
|
||||
|
||||
@Thunk final ArrayMap<LayoutParams, Animator> mReorderAnimators = new ArrayMap<>();
|
||||
@Thunk final ArrayMap<View, ReorderPreviewAnimation> mShakeAnimators = new ArrayMap<>();
|
||||
@Thunk final ArrayMap<Reorderable, ReorderPreviewAnimation> mShakeAnimators = new ArrayMap<>();
|
||||
|
||||
private boolean mItemPlacementDirty = false;
|
||||
|
||||
|
@ -1868,10 +1868,11 @@ public class CellLayout extends ViewGroup {
|
|||
boolean skip = mode == ReorderPreviewAnimation.MODE_HINT && solution.intersectingViews
|
||||
!= null && !solution.intersectingViews.contains(child);
|
||||
|
||||
|
||||
LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (c != null && !skip) {
|
||||
ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child, mode, lp.cellX,
|
||||
lp.cellY, c.cellX, c.cellY, c.spanX, c.spanY);
|
||||
if (c != null && !skip && (child instanceof Reorderable)) {
|
||||
ReorderPreviewAnimation rha = new ReorderPreviewAnimation((Reorderable) child,
|
||||
mode, lp.cellX, lp.cellY, c.cellX, c.cellY, c.spanX, c.spanY);
|
||||
rha.animate();
|
||||
}
|
||||
}
|
||||
|
@ -1893,7 +1894,7 @@ public class CellLayout extends ViewGroup {
|
|||
// Class which represents the reorder preview animations. These animations show that an item is
|
||||
// in a temporary state, and hint at where the item will return to.
|
||||
class ReorderPreviewAnimation {
|
||||
final View child;
|
||||
final Reorderable child;
|
||||
float finalDeltaX;
|
||||
float finalDeltaY;
|
||||
float initDeltaX;
|
||||
|
@ -1913,8 +1914,8 @@ public class CellLayout extends ViewGroup {
|
|||
float animationProgress = 0;
|
||||
ValueAnimator a;
|
||||
|
||||
public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
|
||||
int cellY1, int spanX, int spanY) {
|
||||
public ReorderPreviewAnimation(Reorderable child, int mode, int cellX0, int cellY0,
|
||||
int cellX1, int cellY1, int spanX, int spanY) {
|
||||
regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
|
||||
final int x0 = mTmpPoint[0];
|
||||
final int y0 = mTmpPoint[1];
|
||||
|
@ -1926,63 +1927,60 @@ public class CellLayout extends ViewGroup {
|
|||
|
||||
this.child = child;
|
||||
this.mode = mode;
|
||||
finalDeltaX = 0;
|
||||
finalDeltaY = 0;
|
||||
|
||||
child.getReorderOffset(mTmpPointF);
|
||||
initDeltaX = mTmpPointF.x;
|
||||
initDeltaY = mTmpPointF.y;
|
||||
initScale = child.getReorderScale();
|
||||
finalScale = mChildScale - (CHILD_DIVIDEND / child.getView().getWidth()) * initScale;
|
||||
|
||||
// TODO issue!
|
||||
setInitialAnimationValues(false);
|
||||
finalScale = (mChildScale - (CHILD_DIVIDEND / child.getWidth())) * initScale;
|
||||
finalDeltaX = initDeltaX;
|
||||
finalDeltaY = initDeltaY;
|
||||
int dir = mode == MODE_HINT ? -1 : 1;
|
||||
if (dX == dY && dX == 0) {
|
||||
} else {
|
||||
if (dY == 0) {
|
||||
finalDeltaX += - dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
|
||||
finalDeltaX = -dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
|
||||
} else if (dX == 0) {
|
||||
finalDeltaY += - dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
|
||||
finalDeltaY = -dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
|
||||
} else {
|
||||
double angle = Math.atan( (float) (dY) / dX);
|
||||
finalDeltaX += (int) (- dir * Math.signum(dX) *
|
||||
Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
|
||||
finalDeltaY += (int) (- dir * Math.signum(dY) *
|
||||
Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
|
||||
finalDeltaX = (int) (-dir * Math.signum(dX)
|
||||
* Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
|
||||
finalDeltaY = (int) (-dir * Math.signum(dY)
|
||||
* Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setInitialAnimationValues(boolean restoreOriginalValues) {
|
||||
if (restoreOriginalValues) {
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
|
||||
initScale = lahv.getScaleToFit();
|
||||
initDeltaX = lahv.getTranslationForCentering().x;
|
||||
initDeltaY = lahv.getTranslationForCentering().y;
|
||||
} else {
|
||||
initScale = mChildScale;
|
||||
initDeltaX = 0;
|
||||
initDeltaY = 0;
|
||||
}
|
||||
} else {
|
||||
initScale = child.getScaleX();
|
||||
initDeltaX = child.getTranslationX();
|
||||
initDeltaY = child.getTranslationY();
|
||||
}
|
||||
void setInitialAnimationValuesToBaseline() {
|
||||
initScale = mChildScale;
|
||||
initDeltaX = 0;
|
||||
initDeltaY = 0;
|
||||
}
|
||||
|
||||
void animate() {
|
||||
boolean noMovement = (finalDeltaX == initDeltaX) && (finalDeltaY == initDeltaY);
|
||||
boolean noMovement = (finalDeltaX == 0) && (finalDeltaY == 0);
|
||||
|
||||
if (mShakeAnimators.containsKey(child)) {
|
||||
ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child);
|
||||
oldAnimation.cancel();
|
||||
mShakeAnimators.remove(child);
|
||||
|
||||
if (noMovement) {
|
||||
completeAnimationImmediately();
|
||||
// A previous animation for this item exists, and no new animation will exist.
|
||||
// Finish the old animation smoothly.
|
||||
oldAnimation.finishAnimation();
|
||||
return;
|
||||
} else {
|
||||
// A previous animation for this item exists, and a new one will exist. Stop
|
||||
// the old animation in its tracks, and proceed with the new one.
|
||||
oldAnimation.cancel();
|
||||
}
|
||||
}
|
||||
if (noMovement) {
|
||||
return;
|
||||
}
|
||||
|
||||
ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
|
||||
a = va;
|
||||
|
||||
|
@ -1999,7 +1997,7 @@ public class CellLayout extends ViewGroup {
|
|||
va.addListener(new AnimatorListenerAdapter() {
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
// We make sure to end only after a full period
|
||||
setInitialAnimationValues(true);
|
||||
setInitialAnimationValuesToBaseline();
|
||||
repeating = true;
|
||||
}
|
||||
});
|
||||
|
@ -2012,11 +2010,9 @@ public class CellLayout extends ViewGroup {
|
|||
float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
|
||||
float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
|
||||
float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
|
||||
child.setTranslationX(x);
|
||||
child.setTranslationY(y);
|
||||
child.setReorderOffset(x, y);
|
||||
float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
|
||||
child.setScaleX(s);
|
||||
child.setScaleY(s);
|
||||
child.setReorderScale(s);
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
|
@ -2025,27 +2021,27 @@ public class CellLayout extends ViewGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Thunk void completeAnimationImmediately() {
|
||||
/**
|
||||
* Smoothly returns the item to its baseline position / scale
|
||||
*/
|
||||
@Thunk void finishAnimation() {
|
||||
if (a != null) {
|
||||
a.cancel();
|
||||
}
|
||||
|
||||
setInitialAnimationValues(true);
|
||||
a = new PropertyListBuilder()
|
||||
.scale(initScale)
|
||||
.translationX(initDeltaX)
|
||||
.translationY(initDeltaY)
|
||||
.build(child)
|
||||
.setDuration(REORDER_ANIMATION_DURATION);
|
||||
Launcher.cast(mActivity).getDragController().addFirstFrameAnimationHelper(a);
|
||||
setInitialAnimationValuesToBaseline();
|
||||
ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS,
|
||||
animationProgress, 0);
|
||||
a = va;
|
||||
a.setInterpolator(DEACCEL_1_5);
|
||||
a.setDuration(REORDER_ANIMATION_DURATION);
|
||||
a.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void completeAndClearReorderPreviewAnimations() {
|
||||
for (ReorderPreviewAnimation a: mShakeAnimators.values()) {
|
||||
a.completeAnimationImmediately();
|
||||
a.finishAnimation();
|
||||
}
|
||||
mShakeAnimators.clear();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.View;
|
||||
|
||||
public interface Reorderable {
|
||||
|
||||
/**
|
||||
* Set the offset related to reorder hint and "bounce" animations
|
||||
*/
|
||||
void setReorderOffset(float x, float y);
|
||||
|
||||
void getReorderOffset(PointF offset);
|
||||
|
||||
/**
|
||||
* Set the scale related to reorder hint and "bounce" animations
|
||||
*/
|
||||
void setReorderScale(float scale);
|
||||
float getReorderScale();
|
||||
|
||||
/**
|
||||
* Get the com.android.view related to this object
|
||||
*/
|
||||
View getView();
|
||||
}
|
|
@ -26,6 +26,7 @@ import android.animation.AnimatorListenerAdapter;
|
|||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
@ -49,6 +50,7 @@ import com.android.launcher3.Launcher;
|
|||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.OnAlarmListener;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Reorderable;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
|
@ -79,7 +81,7 @@ import java.util.function.Predicate;
|
|||
* An icon that can appear on in the workspace representing an {@link Folder}.
|
||||
*/
|
||||
public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
|
||||
DraggableView {
|
||||
DraggableView, Reorderable {
|
||||
|
||||
@Thunk ActivityContext mActivity;
|
||||
@Thunk Folder mFolder;
|
||||
|
@ -119,6 +121,9 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||
private float mDotScale;
|
||||
private Animator mDotScaleAnim;
|
||||
|
||||
private final PointF mTranslationForReorder = new PointF(0, 0);
|
||||
private float mScaleForReorder = 1f;
|
||||
|
||||
private static final Property<FolderIcon, Float> DOT_SCALE_PROPERTY
|
||||
= new Property<FolderIcon, Float>(Float.TYPE, "dotScale") {
|
||||
@Override
|
||||
|
@ -226,16 +231,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||
mBackground.getBounds(outBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return DRAGGABLE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVisualDragBounds(Rect bounds) {
|
||||
getPreviewBounds(bounds);
|
||||
}
|
||||
|
||||
public float getBackgroundStrokeWidth() {
|
||||
return mBackground.getStrokeWidth();
|
||||
}
|
||||
|
@ -716,4 +711,39 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||
public void onFolderClose(int currentPage) {
|
||||
mPreviewItemManager.onFolderClose(currentPage);
|
||||
}
|
||||
|
||||
|
||||
public void setReorderOffset(float x, float y) {
|
||||
mTranslationForReorder.set(x, y);
|
||||
super.setTranslationX(x);
|
||||
super.setTranslationY(y);
|
||||
}
|
||||
|
||||
public void getReorderOffset(PointF offset) {
|
||||
offset.set(mTranslationForReorder);
|
||||
}
|
||||
|
||||
public void setReorderScale(float scale) {
|
||||
mScaleForReorder = scale;
|
||||
super.setScaleX(scale);
|
||||
super.setScaleY(scale);
|
||||
}
|
||||
|
||||
public float getReorderScale() {
|
||||
return mScaleForReorder;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return DRAGGABLE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVisualDragBounds(Rect bounds) {
|
||||
getPreviewBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ package com.android.launcher3.widget;
|
|||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
@ -40,7 +38,6 @@ import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
|||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DraggableView;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.util.Executors;
|
||||
|
@ -51,7 +48,7 @@ import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
implements TouchCompleteListener, View.OnLongClickListener, DraggableView {
|
||||
implements TouchCompleteListener, View.OnLongClickListener {
|
||||
|
||||
// Related to the auto-advancing of widgets
|
||||
private static final long ADVANCE_INTERVAL = 20000;
|
||||
|
@ -73,15 +70,7 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
|||
private boolean mIsAutoAdvanceRegistered;
|
||||
private Runnable mAutoAdvanceRunnable;
|
||||
|
||||
/**
|
||||
* The scaleX and scaleY value such that the widget fits within its cellspans, scaleX = scaleY.
|
||||
*/
|
||||
private float mScaleToFit = 1f;
|
||||
|
||||
/**
|
||||
* The translation values to center the widget within its cellspans.
|
||||
*/
|
||||
private final PointF mTranslationForCentering = new PointF(0, 0);
|
||||
|
||||
public LauncherAppWidgetHostView(Context context) {
|
||||
super(context);
|
||||
|
@ -307,26 +296,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
|||
scheduleNextAdvance();
|
||||
}
|
||||
|
||||
public void setScaleToFit(float scale) {
|
||||
mScaleToFit = scale;
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
}
|
||||
|
||||
public float getScaleToFit() {
|
||||
return mScaleToFit;
|
||||
}
|
||||
|
||||
public void setTranslationForCentering(float x, float y) {
|
||||
mTranslationForCentering.set(x, y);
|
||||
setTranslationX(x);
|
||||
setTranslationY(y);
|
||||
}
|
||||
|
||||
public PointF getTranslationForCentering() {
|
||||
return mTranslationForCentering;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
@ -357,17 +326,4 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return DRAGGABLE_WIDGET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVisualDragBounds(Rect bounds) {
|
||||
int width = (int) (getMeasuredWidth() * mScaleToFit);
|
||||
int height = (int) (getMeasuredHeight() * mScaleToFit);
|
||||
|
||||
bounds.set(0, 0 , width, height);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,14 @@ package com.android.launcher3.widget;
|
|||
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.Reorderable;
|
||||
import com.android.launcher3.dragndrop.DraggableView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -32,7 +34,20 @@ import java.util.ArrayList;
|
|||
* Extension of AppWidgetHostView with support for controlled keyboard navigation.
|
||||
*/
|
||||
public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
|
||||
implements DraggableView {
|
||||
implements DraggableView, Reorderable {
|
||||
|
||||
/**
|
||||
* The scaleX and scaleY value such that the widget fits within its cellspans, scaleX = scaleY.
|
||||
*/
|
||||
private float mScaleToFit = 1f;
|
||||
|
||||
/**
|
||||
* The translation values to center the widget within its cellspans.
|
||||
*/
|
||||
private final PointF mTranslationForCentering = new PointF(0, 0);
|
||||
|
||||
private final PointF mTranslationForReorder = new PointF(0, 0);
|
||||
private float mScaleForReorder = 1f;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mChildrenFocused;
|
||||
|
@ -137,6 +152,47 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
|
|||
setSelected(childIsFocused);
|
||||
}
|
||||
|
||||
public void setScaleToFit(float scale) {
|
||||
mScaleToFit = scale;
|
||||
super.setScaleX(scale * mScaleForReorder);
|
||||
super.setScaleY(scale * mScaleForReorder);
|
||||
}
|
||||
|
||||
public float getScaleToFit() {
|
||||
return mScaleToFit;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void setTranslationForCentering(float x, float y) {
|
||||
mTranslationForCentering.set(x, y);
|
||||
super.setTranslationX(x + mTranslationForReorder.x);
|
||||
super.setTranslationY(y + mTranslationForReorder.y);
|
||||
}
|
||||
|
||||
public void setReorderOffset(float x, float y) {
|
||||
mTranslationForReorder.set(x, y);
|
||||
super.setTranslationX(mTranslationForCentering.x + x);
|
||||
super.setTranslationY(mTranslationForCentering.y + y);
|
||||
}
|
||||
|
||||
public void getReorderOffset(PointF offset) {
|
||||
offset.set(mTranslationForReorder);
|
||||
}
|
||||
|
||||
public void setReorderScale(float scale) {
|
||||
mScaleForReorder = scale;
|
||||
super.setScaleX(mScaleToFit * scale);
|
||||
super.setScaleY(mScaleToFit * scale);
|
||||
}
|
||||
|
||||
public float getReorderScale() {
|
||||
return mScaleForReorder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return DRAGGABLE_WIDGET;
|
||||
|
@ -144,6 +200,9 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
|
|||
|
||||
@Override
|
||||
public void getVisualDragBounds(Rect bounds) {
|
||||
bounds.set(0, 0 , getMeasuredWidth(), getMeasuredHeight());
|
||||
int width = (int) (getMeasuredWidth() * mScaleToFit);
|
||||
int height = (int) (getMeasuredHeight() * mScaleToFit);
|
||||
|
||||
bounds.set(0, 0 , width, height);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue