Initial changes to creating a fake landscape Launcher UI

Workspace and hotseat are drawn in rotated UI giving the impression that the
device is in Portrait, even though it is in landscape

Bug: 131360075
Change-Id: I29c4068af25fd4dcf7039b9a45886e864a137977
This commit is contained in:
Sunny Goyal
2019-04-30 12:04:37 -07:00
parent c2803ec5b2
commit ae6e318711
24 changed files with 611 additions and 222 deletions
@@ -116,7 +116,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
} else {
workspaceView = null;
}
final Rect iconLocation = new Rect();
final RectF iconLocation = new RectF();
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
final FloatingIconView floatingView = canUseWorkspaceView
? FloatingIconView.getFloatingIconView(activity, workspaceView,
@@ -138,7 +138,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
if (canUseWorkspaceView) {
return new RectF(iconLocation);
return iconLocation;
} else {
// Fallback to animate to center of screen.
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
@@ -52,7 +52,7 @@ public class TaskViewDrawable extends Drawable {
private final RecentsView mParent;
private final View mIconView;
private final int[] mIconPos;
private final float[] mIconPos;
private final TaskView mTaskView;
private final TaskThumbnailView mThumbnailView;
@@ -68,7 +68,7 @@ public class TaskViewDrawable extends Drawable {
mParent = parent;
mTaskView = tv;
mIconView = tv.getIconView();
mIconPos = new int[2];
mIconPos = new float[2];
mIconScale = mIconView.getScaleX();
Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
@@ -408,7 +408,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
*/
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
Rect windowTargetBounds, boolean toggleVisibility) {
Rect bounds = new Rect();
RectF bounds = new RectF();
mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
bounds, true /* isOpening */, mFloatingView);
Rect crop = new Rect();
@@ -423,8 +423,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
// Scale the app icon to take up the entire screen. This simplifies the math when
// animating the app window position / scale.
float smallestSize = Math.min(windowTargetBounds.height(), windowTargetBounds.width());
float maxScaleX = smallestSize / (float) bounds.width();
float maxScaleY = smallestSize / (float) bounds.height();
float maxScaleX = smallestSize / bounds.width();
float maxScaleY = smallestSize / bounds.height();
float scale = Math.max(maxScaleX, maxScaleY);
float startScale = 1f;
if (v instanceof BubbleTextView && !(v.getParent() instanceof DeepShortcutView)) {
@@ -123,12 +123,12 @@ public abstract class BaseRecyclerView extends RecyclerView {
* @param ev MotionEvent in {@param eventSource}
*/
public boolean shouldContainerScroll(MotionEvent ev, View eventSource) {
int[] point = new int[2];
point[0] = (int) ev.getX();
point[1] = (int) ev.getY();
float[] point = new float[2];
point[0] = ev.getX();
point[1] = ev.getY();
Utilities.mapCoordInSelfToDescendant(mScrollbar, eventSource, point);
// IF the MotionEvent is inside the thumb, container should not be pulled down.
if (mScrollbar.shouldBlockIntercept(point[0], point[1])) {
if (mScrollbar.shouldBlockIntercept((int) point[0], (int) point[1])) {
return false;
}
@@ -142,7 +142,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mActivity = ActivityContext.lookupContext(context);
DeviceProfile grid = mActivity.getDeviceProfile();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
@@ -150,18 +149,24 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
int defaultIconSize = grid.iconSizePx;
final int defaultIconSize;
if (display == DISPLAY_WORKSPACE) {
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
} else if (display == DISPLAY_ALL_APPS) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
} else if (display == DISPLAY_FOLDER) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
} else {
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
}
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
+42 -4
View File
@@ -57,12 +57,14 @@ import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.util.CellAndSpan;
import com.android.launcher3.util.GridOccupancy;
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.views.Transposable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import java.lang.annotation.Retention;
@@ -76,7 +78,7 @@ import java.util.Stack;
import androidx.annotation.IntDef;
import androidx.core.view.ViewCompat;
public class CellLayout extends ViewGroup {
public class CellLayout extends ViewGroup implements Transposable {
public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
@@ -182,6 +184,7 @@ public class CellLayout extends ViewGroup {
// Related to accessible drag and drop
private DragAndDropAccessibilityDelegate mTouchHelper;
private boolean mUseTouchHelper = false;
private RotationMode mRotationMode = RotationMode.NORMAL;
public CellLayout(Context context) {
this(context, null);
@@ -203,7 +206,7 @@ public class CellLayout extends ViewGroup {
setClipToPadding(false);
mActivity = ActivityContext.lookupContext(context);
DeviceProfile grid = mActivity.getDeviceProfile();
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
mCellWidth = mCellHeight = -1;
mFixedCellWidth = mFixedCellHeight = -1;
@@ -317,6 +320,24 @@ public class CellLayout extends ViewGroup {
}
}
public void setRotationMode(RotationMode mode) {
if (mRotationMode != mode) {
mRotationMode = mode;
requestLayout();
}
}
@Override
public RotationMode getRotationMode() {
return mRotationMode;
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
mRotationMode.mapRect(left, top, right, bottom, mTempRect);
super.setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
}
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// Always attempt to dispatch hover events to accessibility first.
@@ -745,6 +766,14 @@ public class CellLayout extends ViewGroup {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
mShortcutsAndWidgets.setRotation(mRotationMode.surfaceRotation);
if (mRotationMode.isTransposed) {
int tmp = childWidthSize;
childWidthSize = childHeightSize;
childHeightSize = tmp;
}
if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX);
int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY);
@@ -787,7 +816,6 @@ public class CellLayout extends ViewGroup {
int top = getPaddingTop();
int bottom = b - t - getPaddingBottom();
mShortcutsAndWidgets.layout(left, top, right, bottom);
// Expand the background drawing bounds by the padding baked into the background drawable
mBackground.getPadding(mTempRect);
mBackground.setBounds(
@@ -795,6 +823,16 @@ public class CellLayout extends ViewGroup {
top - mTempRect.top - getPaddingTop(),
right + mTempRect.right + getPaddingRight(),
bottom + mTempRect.bottom + getPaddingBottom());
if (mRotationMode.isTransposed) {
int halfW = mShortcutsAndWidgets.getMeasuredWidth() / 2;
int halfH = mShortcutsAndWidgets.getMeasuredHeight() / 2;
int cX = (left + right) / 2;
int cY = (top + bottom) / 2;
mShortcutsAndWidgets.layout(cX - halfW, cY - halfH, cX + halfW, cY + halfH);
} else {
mShortcutsAndWidgets.layout(left, top, right, bottom);
}
}
/**
@@ -929,7 +967,7 @@ public class CellLayout extends ViewGroup {
if (resize) {
cellToRect(cellX, cellY, spanX, spanY, r);
if (v instanceof LauncherAppWidgetHostView) {
DeviceProfile profile = mActivity.getDeviceProfile();
DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
}
} else {
+4 -39
View File
@@ -419,6 +419,10 @@ public class DeviceProfile {
updateWorkspacePadding();
}
/**
* The current device insets. This is generally same as the insets being dispatched to
* {@link Insettable} elements, but can differ if the element is using a different profile.
*/
public Rect getInsets() {
return mInsets;
}
@@ -582,45 +586,6 @@ public class DeviceProfile {
}
}
/**
* Gets an item's location on the home screen. This is useful if the home screen
* is animating, otherwise use {@link View#getLocationOnScreen(int[])}.
* @param pageDiff The page difference relative to the current page.
*/
public void getItemLocation(int cellX, int cellY, int spanX, int spanY, int container,
int pageDiff, Rect outBounds) {
outBounds.setEmpty();
if (container == CONTAINER_HOTSEAT) {
final int actualHotseatCellHeight;
if (isVerticalBarLayout()) {
actualHotseatCellHeight = availableHeightPx / inv.numRows;
if (mIsSeascape) {
outBounds.left = mHotseatPadding.left;
} else {
outBounds.left = availableWidthPx - hotseatBarSizePx + mHotseatPadding.left;
}
outBounds.right = outBounds.left + iconSizePx;
outBounds.top = mHotseatPadding.top
+ actualHotseatCellHeight * (inv.numRows - cellX - 1);
outBounds.bottom = outBounds.top + actualHotseatCellHeight;
} else {
actualHotseatCellHeight = hotseatBarSizePx - hotseatBarBottomPaddingPx
- hotseatBarTopPaddingPx;
outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
+ (cellX * getCellSize().x);
outBounds.right = outBounds.left + getCellSize().x;
outBounds.top = mInsets.top + availableHeightPx - hotseatBarSizePx;
outBounds.bottom = outBounds.top + actualHotseatCellHeight;
}
} else {
outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
+ (cellX * getCellSize().x) + (pageDiff * availableWidthPx);
outBounds.right = outBounds.left + (getCellSize().x * spanX);
outBounds.top = mInsets.top + workspacePadding.top + (cellY * getCellSize().y);
outBounds.bottom = outBounds.top + (getCellSize().y * spanY);
}
}
private static Context getContext(Context c, int orientation) {
Configuration context = new Configuration(c.getResources().getConfiguration());
context.orientation = orientation;
+10 -2
View File
@@ -26,11 +26,13 @@ import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.Transposable;
public class Hotseat extends CellLayout implements LogContainerProvider, Insettable {
public class Hotseat extends CellLayout implements LogContainerProvider, Insettable, Transposable {
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
@@ -77,7 +79,8 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta
@Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = mActivity.getDeviceProfile();
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
insets = grid.getInsets();
if (grid.isVerticalBarLayout()) {
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -105,4 +108,9 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta
// Don't let if follow through to workspace
return true;
}
@Override
public RotationMode getRotationMode() {
return Launcher.getLauncher(getContext()).getRotationMode();
}
}
+51 -2
View File
@@ -53,6 +53,7 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -71,6 +72,7 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
@@ -93,6 +95,7 @@ import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
@@ -272,6 +275,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
private float mCurrentAssistantVisibility = 0f;
private DeviceProfile mStableDeviceProfile;
private RotationMode mRotationMode = RotationMode.NORMAL;
@Override
protected void onCreate(Bundle savedInstanceState) {
RaceConditionTracker.onEvent(ON_CREATE_EVT, ENTER);
@@ -390,6 +396,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
}
}
});
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
getWindow().setAttributes(lp);
}
}
@Override
@@ -418,6 +430,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void reapplyUi() {
if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
mRotationMode = mStableDeviceProfile == null ? RotationMode.NORMAL :
(mDeviceProfile.isSeascape() ? RotationMode.SEASCAPE : RotationMode.LANDSCAPE);
}
getRootView().dispatchInsets();
getStateManager().reapplyState(true /* cancelCurrentAnimation */);
}
@@ -469,8 +485,41 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
display.getSize(mwSize);
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
}
if (FeatureFlags.FAKE_LANDSCAPE_UI.get() && mDeviceProfile.isVerticalBarLayout()
&& !mDeviceProfile.isMultiWindowMode) {
mStableDeviceProfile = mDeviceProfile.inv.portraitProfile;
mRotationMode = mDeviceProfile.isSeascape()
? RotationMode.SEASCAPE : RotationMode.LANDSCAPE;
} else {
mStableDeviceProfile = null;
mRotationMode = RotationMode.NORMAL;
}
onDeviceProfileInitiated();
mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout(), true);
mModelWriter = mModel.getWriter(getWallpaperDeviceProfile().isVerticalBarLayout(), true);
}
public void updateInsets(Rect insets) {
mDeviceProfile.updateInsets(insets);
if (mStableDeviceProfile != null) {
mStableDeviceProfile.updateInsets(insets);
}
}
@Override
public RotationMode getRotationMode() {
return mRotationMode;
}
/**
* Device profile to be used by UI elements which are shown directly on top of the wallpaper
* and whose presentation is tied to the wallpaper (and physical device) and not the activity
* configuration.
*/
@Override
public DeviceProfile getWallpaperDeviceProfile() {
return mStableDeviceProfile == null ? mDeviceProfile : mStableDeviceProfile;
}
public RotationHelper getRotationHelper() {
@@ -1812,7 +1861,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mAppWidgetHost.clearViews();
if (mHotseat != null) {
mHotseat.resetLayout(mDeviceProfile.isVerticalBarLayout());
mHotseat.resetLayout(getWallpaperDeviceProfile().isVerticalBarLayout());
}
TraceHelper.endSection("startBinding");
}
@@ -81,7 +81,7 @@ public class LauncherRootView extends InsettableFrameLayout {
UI_STATE_ROOT_VIEW, drawInsetBar ? FLAG_DARK_NAV : 0);
// Update device profile before notifying th children.
mLauncher.getDeviceProfile().updateInsets(insets);
mLauncher.updateInsets(insets);
boolean resetState = !insets.equals(mInsets);
setInsets(insets);
@@ -114,7 +114,7 @@ public class LauncherRootView extends InsettableFrameLayout {
}
public void dispatchInsets() {
mLauncher.getDeviceProfile().updateInsets(mInsets);
mLauncher.updateInsets(mInsets);
super.setInsets(mInsets);
}
@@ -93,7 +93,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
public void setupLp(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (child instanceof LauncherAppWidgetHostView) {
DeviceProfile profile = mActivity.getDeviceProfile();
DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
profile.appWidgetScale.x, profile.appWidgetScale.y);
} else {
@@ -108,12 +108,12 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
public int getCellContentHeight() {
return Math.min(getMeasuredHeight(),
mActivity.getDeviceProfile().getCellHeight(mContainerType));
mActivity.getWallpaperDeviceProfile().getCellHeight(mContainerType));
}
public void measureChild(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
final DeviceProfile profile = mActivity.getDeviceProfile();
final DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
if (child instanceof LauncherAppWidgetHostView) {
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
+55 -73
View File
@@ -16,9 +16,6 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.WallpaperManager;
@@ -63,13 +60,12 @@ import android.view.animation.Interpolator;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.views.Transposable;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.io.Closeable;
@@ -97,7 +93,6 @@ public final class Utilities {
private static final int[] sLoc0 = new int[2];
private static final int[] sLoc1 = new int[2];
private static final float[] sPoint = new float[2];
private static final Matrix sMatrix = new Matrix();
private static final Matrix sInverseMatrix = new Matrix();
@@ -143,7 +138,7 @@ public final class Utilities {
*/
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
public static boolean IS_RUNNING_IN_TEST_HARNESS =
ActivityManager.isRunningInTestHarness();
@@ -170,37 +165,60 @@ public final class Utilities {
* assumption fails, we will need to return a pair of scale factors.
*/
public static float getDescendantCoordRelativeToAncestor(
View descendant, View ancestor, int[] coord, boolean includeRootScroll) {
sPoint[0] = coord[0];
sPoint[1] = coord[1];
View descendant, View ancestor, float[] coord, boolean includeRootScroll) {
return getDescendantCoordRelativeToAncestor(descendant, ancestor, coord, includeRootScroll,
false);
}
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
*
* @param descendant The descendant to which the passed coordinate is relative.
* @param ancestor The root view to make the coordinates relative to.
* @param coord The coordinate that we want mapped.
* @param includeRootScroll Whether or not to account for the scroll of the descendant:
* sometimes this is relevant as in a child's coordinates within the descendant.
* @param ignoreTransform If true, view transform is ignored
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public static float getDescendantCoordRelativeToAncestor(View descendant, View ancestor,
float[] coord, boolean includeRootScroll, boolean ignoreTransform) {
float scale = 1.0f;
View v = descendant;
while(v != ancestor && v != null) {
// For TextViews, scroll has a meaning which relates to the text position
// which is very strange... ignore the scroll.
if (v != descendant || includeRootScroll) {
sPoint[0] -= v.getScrollX();
sPoint[1] -= v.getScrollY();
offsetPoints(coord, -v.getScrollX(), -v.getScrollY());
}
v.getMatrix().mapPoints(sPoint);
sPoint[0] += v.getLeft();
sPoint[1] += v.getTop();
if (ignoreTransform) {
if (v instanceof Transposable) {
RotationMode m = ((Transposable) v).getRotationMode();
if (m.isTransposed) {
sMatrix.setRotate(m.surfaceRotation, v.getPivotX(), v.getPivotY());
sMatrix.mapPoints(coord);
}
}
} else {
v.getMatrix().mapPoints(coord);
}
offsetPoints(coord, v.getLeft(), v.getTop());
scale *= v.getScaleX();
v = (View) v.getParent();
}
coord[0] = Math.round(sPoint[0]);
coord[1] = Math.round(sPoint[1]);
return scale;
}
/**
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, int[], boolean)}.
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
*/
public static void mapCoordInSelfToDescendant(View descendant, View root, int[] coord) {
public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
sMatrix.reset();
View v = descendant;
while(v != root) {
@@ -211,12 +229,23 @@ public final class Utilities {
}
sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
sMatrix.invert(sInverseMatrix);
sInverseMatrix.mapPoints(coord);
}
sPoint[0] = coord[0];
sPoint[1] = coord[1];
sInverseMatrix.mapPoints(sPoint);
coord[0] = Math.round(sPoint[0]);
coord[1] = Math.round(sPoint[1]);
/**
* Sets {@param out} to be same as {@param in} by rounding individual values
*/
public static void roundArray(float[] in, int[] out) {
for (int i = 0; i < in.length; i++) {
out[i] = Math.round(in[i]);
}
}
public static void offsetPoints(float[] points, float offsetX, float offsetY) {
for (int i = 0; i < points.length; i += 2) {
points[i] += offsetX;
points[i + 1] += offsetY;
}
}
/**
@@ -569,53 +598,6 @@ public final class Utilities {
return String.format(Locale.ENGLISH, "%d,%d", x, y);
}
/**
* Returns the location bounds of a view.
* - For DeepShortcutView, we return the bounds of the icon view.
* - For BubbleTextView, we return the icon bounds.
*/
public static void getLocationBoundsForView(Launcher launcher, View v, Rect outRect) {
final DragLayer dragLayer = launcher.getDragLayer();
final boolean isBubbleTextView = v instanceof BubbleTextView;
final boolean isFolderIcon = v instanceof FolderIcon;
final Rect rect = new Rect();
// Deep shortcut views have their icon drawn in a separate view.
final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
if (v instanceof DeepShortcutView) {
dragLayer.getDescendantRectRelativeToSelf(((DeepShortcutView) v).getIconView(), rect);
} else if (fromDeepShortcutView) {
DeepShortcutView view = (DeepShortcutView) v.getParent();
dragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect);
} else if ((isBubbleTextView || isFolderIcon) && v.getTag() instanceof ItemInfo
&& (((ItemInfo) v.getTag()).container == CONTAINER_DESKTOP
|| ((ItemInfo) v.getTag()).container == CONTAINER_HOTSEAT)) {
CellLayout pageViewIsOn = ((CellLayout) v.getParent().getParent());
int pageNum = launcher.getWorkspace().indexOfChild(pageViewIsOn);
DeviceProfile dp = launcher.getDeviceProfile();
ItemInfo info = ((ItemInfo) v.getTag());
dp.getItemLocation(info.cellX, info.cellY, info.spanX, info.spanY,
info.container, pageNum - launcher.getCurrentWorkspaceScreen(), rect);
} else {
dragLayer.getDescendantRectRelativeToSelf(v, rect);
}
int viewLocationLeft = rect.left;
int viewLocationTop = rect.top;
if (isBubbleTextView && !fromDeepShortcutView) {
((BubbleTextView) v).getIconBounds(rect);
} else if (isFolderIcon) {
((FolderIcon) v).getPreviewBounds(rect);
} else {
rect.set(0, 0, rect.width(), rect.height());
}
viewLocationLeft += rect.left;
viewLocationTop += rect.top;
outRect.set(viewLocationLeft, viewLocationTop, viewLocationLeft + rect.width(),
viewLocationTop + rect.height());
}
public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) {
try {
context.unregisterReceiver(receiver);
+42 -43
View File
@@ -82,6 +82,7 @@ import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
@@ -175,7 +176,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
@Thunk final Launcher mLauncher;
@Thunk DragController mDragController;
private final Rect mTempRect = new Rect();
private final int[] mTempXY = new int[2];
private final float[] mTempFXY = new float[2];
@Thunk float[] mDragViewVisualCenter = new float[2];
private final float[] mTempTouchCoordinates = new float[2];
@@ -285,18 +288,23 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
DeviceProfile grid = mLauncher.getDeviceProfile();
mMaxDistanceForFolderCreation = grid.isTablet
? 0.75f * grid.iconSizePx
: 0.55f * grid.iconSizePx;
DeviceProfile stableGrid = mLauncher.getWallpaperDeviceProfile();
mMaxDistanceForFolderCreation = stableGrid.isTablet
? 0.75f * stableGrid.iconSizePx
: 0.55f * stableGrid.iconSizePx;
mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
Rect padding = grid.workspacePadding;
setPadding(padding.left, padding.top, padding.right, padding.bottom);
Rect padding = stableGrid.workspacePadding;
if (grid.shouldFadeAdjacentWorkspaceScreens()) {
RotationMode rotationMode = mLauncher.getRotationMode();
rotationMode.mapRect(padding, mTempRect);
setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
rotationMode.mapRect(insets, mInsets);
if (mWorkspaceFadeInAdjacentScreens) {
// In landscape mode the page spacing is set to the default.
setPageSpacing(grid.edgeMarginPx);
} else {
@@ -306,11 +314,13 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
setPageSpacing(Math.max(grid.edgeMarginPx, padding.left + 1));
}
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
int paddingBottom = grid.cellLayoutBottomPaddingPx;
int paddingLeftRight = stableGrid.cellLayoutPaddingLeftRightPx;
int paddingBottom = stableGrid.cellLayoutBottomPaddingPx;
for (int i = mWorkspaceScreens.size() - 1; i >= 0; i--) {
mWorkspaceScreens.valueAt(i)
.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
CellLayout page = mWorkspaceScreens.valueAt(i);
page.setRotationMode(rotationMode);
page.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
}
}
@@ -330,7 +340,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
float scale = 1;
if (isWidget) {
DeviceProfile profile = mLauncher.getDeviceProfile();
DeviceProfile profile = mLauncher.getWallpaperDeviceProfile();
scale = Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
}
size[0] = r.width();
@@ -550,8 +560,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
DeviceProfile grid = mLauncher.getWallpaperDeviceProfile();
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
int paddingBottom = grid.cellLayoutBottomPaddingPx;
newScreen.setRotationMode(mLauncher.getRotationMode());
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
mWorkspaceScreens.put(screenId, newScreen);
@@ -1930,18 +1942,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
if (child == null) {
return;
}
ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
// Use the absolute left instead of the child left, as we want the visible area
// irrespective of the visible child. Since the view can only scroll horizontally, the
// top position is not affected.
mTempXY[0] = getPaddingLeft() + boundingLayout.getLeft();
mTempXY[1] = child.getTop() + boundingLayout.getTop();
float scale = mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY);
outArea.set(mTempXY[0], mTempXY[1],
(int) (mTempXY[0] + scale * boundingLayout.getMeasuredWidth()),
(int) (mTempXY[1] + scale * boundingLayout.getMeasuredHeight()));
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, outArea);
}
@Override
@@ -2094,14 +2097,14 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
}
boolean isPointInSelfOverHotseat(int x, int y) {
mTempXY[0] = x;
mTempXY[1] = y;
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
mTempFXY[0] = x;
mTempFXY[1] = y;
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempFXY, true);
View hotseat = mLauncher.getHotseat();
return mTempXY[0] >= hotseat.getLeft() &&
mTempXY[0] <= hotseat.getRight() &&
mTempXY[1] >= hotseat.getTop() &&
mTempXY[1] <= hotseat.getBottom();
return mTempFXY[0] >= hotseat.getLeft() &&
mTempFXY[0] <= hotseat.getRight() &&
mTempFXY[1] >= hotseat.getTop() &&
mTempFXY[1] <= hotseat.getBottom();
}
/**
@@ -2111,13 +2114,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
*/
private void mapPointFromDropLayout(CellLayout layout, float[] xy) {
if (mLauncher.isHotseatLayout(layout)) {
mTempXY[0] = (int) xy[0];
mTempXY[1] = (int) xy[1];
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
mLauncher.getDragLayer().mapCoordInSelfToDescendant(layout, mTempXY);
xy[0] = mTempXY[0];
xy[1] = mTempXY[1];
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, xy, true);
mLauncher.getDragLayer().mapCoordInSelfToDescendant(layout, xy);
} else {
mapPointFromSelfToChild(layout, xy);
}
@@ -2608,13 +2606,14 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
DeviceProfile profile = mLauncher.getDeviceProfile();
Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
}
loc[0] = r.left;
loc[1] = r.top;
mTempFXY[0] = r.left;
mTempFXY[1] = r.top;
setFinalTransitionTransform();
float cellLayoutScale =
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, mTempFXY, true);
resetTransitionTransform();
Utilities.roundArray(mTempFXY, loc);
if (scale) {
float dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
@@ -93,14 +93,16 @@ public class WorkspaceStateTransitionAnimation {
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
// Set the hotseat's pivot point to match the workspace's, so that it scales together.
DragLayer dragLayer = mLauncher.getDragLayer();
int[] workspacePivot = new int[]{(int) mWorkspace.getPivotX(),
(int) mWorkspace.getPivotY()};
dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
hotseat.setPivotX(workspacePivot[0]);
hotseat.setPivotY(workspacePivot[1]);
if (!hotseat.getRotationMode().isTransposed) {
// Set the hotseat's pivot point to match the workspace's, so that it scales together.
DragLayer dragLayer = mLauncher.getDragLayer();
float[] workspacePivot =
new float[]{ mWorkspace.getPivotX(), mWorkspace.getPivotY() };
dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
hotseat.setPivotX(workspacePivot[0]);
hotseat.setPivotY(workspacePivot[1]);
}
float hotseatScale = hotseatScaleAndTranslation.scale;
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, scaleInterpolator);
@@ -110,6 +110,10 @@ abstract class BaseFlags {
"ENABLE_HINTS_IN_OVERVIEW", false,
"Show chip hints and gleams on the overview screen");
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
"FAKE_LANDSCAPE_UI", false,
"Rotate launcher UI instead of using transposed layout");
public static void initialize(Context context) {
// Avoid the disk read for user builds
if (Utilities.IS_DEBUG_DEVICE) {
@@ -17,6 +17,10 @@
package com.android.launcher3.dragndrop;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
import static android.view.View.MeasureSpec.getSize;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.animation.Animator;
@@ -29,12 +33,14 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
@@ -42,6 +48,7 @@ import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTargetBar;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.Interpolators;
@@ -52,6 +59,7 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.views.Transposable;
import java.util.ArrayList;
@@ -260,10 +268,10 @@ public class DragLayer extends BaseDragLayer<Launcher> {
Rect r = new Rect();
getViewRectRelativeToSelf(dragView, r);
int coord[] = new int[2];
float coord[] = new float[2];
float childScale = child.getScaleX();
coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
coord[0] = lp.x + (child.getMeasuredWidth() * (1 - childScale) / 2);
coord[1] = lp.y + (child.getMeasuredHeight() * (1 - childScale) / 2);
// Since the child hasn't necessarily been laid out, we force the lp to be updated with
// the correct coordinates (above) and use these to determine the final location
@@ -271,8 +279,8 @@ public class DragLayer extends BaseDragLayer<Launcher> {
// We need to account for the scale of the child itself, as the above only accounts for
// for the scale in parents.
scale *= childScale;
int toX = coord[0];
int toY = coord[1];
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
float toScale = scale;
if (child instanceof TextView) {
TextView tv = (TextView) child;
@@ -551,4 +559,159 @@ public class DragLayer extends BaseDragLayer<Launcher> {
public WorkspaceAndHotseatScrim getScrim() {
return mScrim;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
RotationMode rotation = mActivity.getRotationMode();
int count = getChildCount();
if (!rotation.isTransposed
|| getMode(widthMeasureSpec) != EXACTLY
|| getMode(heightMeasureSpec) != EXACTLY) {
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.setRotation(rotation.surfaceRotation);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
if (!(child instanceof Transposable)) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
} else {
measureChildWithMargins(child, heightMeasureSpec, 0, widthMeasureSpec, 0);
child.setPivotX(child.getMeasuredWidth() / 2);
child.setPivotY(child.getMeasuredHeight() / 2);
child.setRotation(rotation.surfaceRotation);
}
}
setMeasuredDimension(getSize(widthMeasureSpec), getSize(heightMeasureSpec));
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
RotationMode rotation = mActivity.getRotationMode();
if (!rotation.isTransposed) {
super.onLayout(changed, left, top, right, bottom);
return;
}
final int count = getChildCount();
final int parentWidth = right - left;
final int parentHeight = bottom - top;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
if (lp instanceof LayoutParams) {
final LayoutParams dlp = (LayoutParams) lp;
if (dlp.customPosition) {
child.layout(dlp.x, dlp.y, dlp.x + dlp.width, dlp.y + dlp.height);
continue;
}
}
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = Gravity.TOP | Gravity.START;
}
final int layoutDirection = getLayoutDirection();
int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
int horizontalGravity = absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
int verticalGravity = absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK;
if (child instanceof Transposable) {
if (rotation == RotationMode.SEASCAPE) {
if (horizontalGravity == Gravity.RIGHT) {
horizontalGravity = Gravity.LEFT;
} else if (horizontalGravity == Gravity.LEFT) {
horizontalGravity = Gravity.RIGHT;
}
if (verticalGravity == Gravity.TOP) {
verticalGravity = Gravity.BOTTOM;
} else if (verticalGravity == Gravity.BOTTOM) {
verticalGravity = Gravity.TOP;
}
}
switch (horizontalGravity) {
case Gravity.CENTER_HORIZONTAL:
childTop = (parentHeight - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.RIGHT:
childTop = width / 2 + lp.rightMargin - height / 2;
break;
case Gravity.LEFT:
default:
childTop = parentHeight - lp.leftMargin - width / 2 - height / 2;
}
switch (verticalGravity) {
case Gravity.CENTER_VERTICAL:
childLeft = (parentWidth - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.BOTTOM:
childLeft = parentWidth - width / 2 - height / 2 - lp.bottomMargin;
break;
case Gravity.TOP:
default:
childLeft = height / 2 - width / 2 + lp.topMargin;
}
} else {
switch (horizontalGravity) {
case Gravity.CENTER_HORIZONTAL:
childLeft = (parentWidth - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = parentWidth - width - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = (parentHeight - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentHeight - height - lp.bottomMargin;
break;
default:
childTop = lp.topMargin;
}
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
+2 -3
View File
@@ -869,7 +869,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
DeviceProfile grid = mLauncher.getDeviceProfile();
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
DragLayer parent = mLauncher.getDragLayer();
int width = getFolderWidth();
int height = getFolderHeight();
@@ -881,8 +881,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// We need to bound the folder to the currently visible workspace area
if (mLauncher.getStateManager().getState().overviewUi) {
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mLauncher.getOverviewPanel(),
sTempRect);
parent.getDescendantRectRelativeToSelf(mLauncher.getOverviewPanel(), sTempRect);
} else {
mLauncher.getWorkspace().getPageAreaRelativeToDragLayer(sTempRect);
}
@@ -159,7 +159,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
"is dependent on this");
}
DeviceProfile grid = launcher.getDeviceProfile();
DeviceProfile grid = launcher.getWallpaperDeviceProfile();
FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext())
.inflate(resId, group, false);
@@ -174,7 +174,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.mInfo = folderInfo;
icon.mLauncher = launcher;
icon.mDotRenderer = launcher.getDeviceProfile().mDotRenderer;
icon.mDotRenderer = grid.mDotRenderer;
icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title));
Folder folder = Folder.fromXml(launcher);
folder.setDragController(launcher.getDragController());
@@ -508,7 +508,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
public void drawDot(Canvas canvas) {
if ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0) {
Rect iconBounds = mDotParams.iconBounds;
BubbleTextView.getIconBounds(this, iconBounds, mLauncher.getDeviceProfile().iconSizePx);
BubbleTextView.getIconBounds(this, iconBounds,
mLauncher.getWallpaperDeviceProfile().iconSizePx);
// If we are animating to the accepting state, animate the dot out.
mDotParams.scale = Math.max(0, mDotScale - mBackground.getScaleProgress());
@@ -42,7 +42,6 @@ import android.view.View;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
/**
@@ -135,7 +134,7 @@ public class PreviewBackground {
mBgColor = ta.getColor(R.styleable.FolderIconPreview_android_colorPrimary, 0);
ta.recycle();
DeviceProfile grid = activity.getDeviceProfile();
DeviceProfile grid = activity.getWallpaperDeviceProfile();
previewSize = grid.folderIconSizePx;
basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2019 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.graphics;
import android.graphics.Rect;
public abstract class RotationMode {
public final float surfaceRotation;
public final boolean isTransposed;
private RotationMode(float surfaceRotation) {
this.surfaceRotation = surfaceRotation;
isTransposed = surfaceRotation != 0;
}
public final void mapRect(Rect rect, Rect out) {
mapRect(rect.left, rect.top, rect.right, rect.bottom, out);
}
public void mapRect(int left, int top, int right, int bottom, Rect out) {
out.set(left, top, right, bottom);
}
public static RotationMode NORMAL = new RotationMode(0) { };
public static RotationMode LANDSCAPE = new RotationMode(-90) {
@Override
public void mapRect(int left, int top, int right, int bottom, Rect out) {
out.left = top;
out.top = right;
out.right = bottom;
out.bottom = left;
}
};
public static RotationMode SEASCAPE = new RotationMode(90) {
@Override
public void mapRect(int left, int top, int right, int bottom, Rect out) {
out.left = bottom;
out.top = left;
out.right = top;
out.bottom = right;
}
};
}
@@ -22,6 +22,7 @@ import android.view.View.AccessibilityDelegate;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.dot.DotInfo;
/**
@@ -56,6 +57,19 @@ public interface ActivityContext {
DeviceProfile getDeviceProfile();
/**
* Device profile to be used by UI elements which are shown directly on top of the wallpaper
* and whose presentation is tied to the wallpaper (and physical device) and not the activity
* configuration.
*/
default DeviceProfile getWallpaperDeviceProfile() {
return getDeviceProfile();
}
default RotationMode getRotationMode() {
return RotationMode.NORMAL;
}
static ActivityContext lookupContext(Context context) {
if (context instanceof ActivityContext) {
return (ActivityContext) context;
@@ -88,7 +88,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
// Touch is being dispatched through a proxy from InputMonitor
private static final int TOUCH_DISPATCHING_PROXY = 1 << 2;
protected final int[] mTmpXY = new int[2];
protected final float[] mTmpXY = new float[2];
protected final float[] mTmpRectPoints = new float[4];
protected final Rect mHitRect = new Rect();
@ViewDebug.ExportedProperty(category = "launcher")
@@ -306,14 +307,16 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
* @return The factor by which this descendant is scaled relative to this DragLayer.
*/
public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
mTmpXY[0] = 0;
mTmpXY[1] = 0;
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
r.set(mTmpXY[0], mTmpXY[1],
(int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
(int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
return scale;
mTmpRectPoints[0] = 0;
mTmpRectPoints[1] = 0;
mTmpRectPoints[2] = descendant.getWidth();
mTmpRectPoints[3] = descendant.getHeight();
float s = getDescendantCoordRelativeToSelf(descendant, mTmpRectPoints);
r.left = Math.round(Math.min(mTmpRectPoints[0], mTmpRectPoints[2]));
r.top = Math.round(Math.min(mTmpRectPoints[1], mTmpRectPoints[3]));
r.right = Math.round(Math.max(mTmpRectPoints[0], mTmpRectPoints[2]));
r.bottom = Math.round(Math.max(mTmpRectPoints[1], mTmpRectPoints[3]));
return s;
}
public float getLocationInDragLayer(View child, int[] loc) {
@@ -323,6 +326,14 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
}
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
mTmpXY[0] = coord[0];
mTmpXY[1] = coord[1];
float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
Utilities.roundArray(mTmpXY, coord);
return scale;
}
public float getDescendantCoordRelativeToSelf(View descendant, float[] coord) {
return getDescendantCoordRelativeToSelf(descendant, coord, false);
}
@@ -338,17 +349,27 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
public float getDescendantCoordRelativeToSelf(View descendant, float[] coord,
boolean includeRootScroll) {
return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
coord, includeRootScroll);
}
/**
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, float[])}.
*/
public void mapCoordInSelfToDescendant(View descendant, float[] coord) {
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
}
/**
* Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
*/
public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
mTmpXY[0] = coord[0];
mTmpXY[1] = coord[1];
Utilities.mapCoordInSelfToDescendant(descendant, this, mTmpXY);
Utilities.roundArray(mTmpXY, coord);
}
public void getViewRectRelativeToSelf(View v, Rect r) {
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.views;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -23,6 +26,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -61,12 +65,10 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import static com.android.launcher3.Utilities.mapToRange;
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
@TargetApi(Build.VERSION_CODES.Q)
public class FloatingIconView extends View implements Animator.AnimatorListener, ClipPathView {
public static final float SHAPE_PROGRESS_DURATION = 0.15f;
@@ -186,14 +188,16 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
* @param v The view to copy
* @param positionOut Rect that will hold the size and position of v.
*/
private void matchPositionOf(Launcher launcher, View v, Rect positionOut) {
Utilities.getLocationBoundsForView(launcher, v, positionOut);
final LayoutParams lp = new LayoutParams(positionOut.width(), positionOut.height());
private void matchPositionOf(Launcher launcher, View v, RectF positionOut) {
getLocationBoundsForView(launcher, v, positionOut);
final LayoutParams lp = new LayoutParams(
Math.round(positionOut.width()),
Math.round(positionOut.height()));
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
lp.leftMargin = positionOut.left;
lp.topMargin = positionOut.top;
lp.leftMargin = Math.round(positionOut.left);
lp.topMargin = Math.round(positionOut.top);
setLayoutParams(lp);
// Set the properties here already to make sure they are available when running the first
// animation frame.
@@ -201,6 +205,57 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
+ lp.height);
}
/**
* Returns the location bounds of a view.
* - For DeepShortcutView, we return the bounds of the icon view.
* - For BubbleTextView, we return the icon bounds.
*/
private void getLocationBoundsForView(Launcher launcher, View v, RectF outRect) {
final boolean isBubbleTextView = v instanceof BubbleTextView;
final boolean isFolderIcon = v instanceof FolderIcon;
// Deep shortcut views have their icon drawn in a separate view.
final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
final View targetView;
boolean ignoreTransform = false;
if (v instanceof DeepShortcutView) {
targetView = ((DeepShortcutView) v).getIconView();
} else if (fromDeepShortcutView) {
DeepShortcutView view = (DeepShortcutView) v.getParent();
targetView = view.getIconView();
} else if ((isBubbleTextView || isFolderIcon) && v.getTag() instanceof ItemInfo
&& (((ItemInfo) v.getTag()).container == CONTAINER_DESKTOP
|| ((ItemInfo) v.getTag()).container == CONTAINER_HOTSEAT)) {
targetView = v;
ignoreTransform = true;
} else {
targetView = v;
}
float[] points = new float[] {0, 0, targetView.getWidth(), targetView.getHeight()};
Utilities.getDescendantCoordRelativeToAncestor(targetView, launcher.getDragLayer(), points,
false, ignoreTransform);
float viewLocationLeft = Math.min(points[0], points[2]);
float viewLocationTop = Math.min(points[1], points[3]);
final Rect iconRect = new Rect();
if (isBubbleTextView && !fromDeepShortcutView) {
((BubbleTextView) v).getIconBounds(iconRect);
} else if (isFolderIcon) {
((FolderIcon) v).getPreviewBounds(iconRect);
} else {
iconRect.set(0, 0, Math.abs(Math.round(points[2] - points[0])),
Math.abs(Math.round(points[3] - points[1])));
}
viewLocationLeft += iconRect.left;
viewLocationTop += iconRect.top;
outRect.set(viewLocationLeft, viewLocationTop, viewLocationLeft + iconRect.width(),
viewLocationTop + iconRect.height());
}
@WorkerThread
private void getIcon(Launcher launcher, View v, ItemInfo info, boolean isOpening,
Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
@@ -411,7 +466,7 @@ public class FloatingIconView extends View implements Animator.AnimatorListener,
* @param isOpening True if this view replaces the icon for app open animation.
*/
public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
boolean hideOriginal, Rect positionOut, boolean isOpening, FloatingIconView recycle) {
boolean hideOriginal, RectF positionOut, boolean isOpening, FloatingIconView recycle) {
if (recycle != null) {
recycle.recycle();
}
@@ -0,0 +1,26 @@
/**
* Copyright (C) 2019 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.views;
import com.android.launcher3.graphics.RotationMode;
/**
* Indicates that a view can be transposed.
*/
public interface Transposable {
RotationMode getRotationMode();
}