diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2019-04-30 12:04:37 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2019-05-02 10:59:28 -0700 |
commit | ae6e318711239601fdd11a14c3cf8c542b808f19 (patch) | |
tree | cc648803791d551f80202267b1c05ca6f1084517 /src/com/android/launcher3 | |
parent | c2803ec5b272c902b6ab314d782afe852163b4ff (diff) | |
download | android_packages_apps_Trebuchet-ae6e318711239601fdd11a14c3cf8c542b808f19.tar.gz android_packages_apps_Trebuchet-ae6e318711239601fdd11a14c3cf8c542b808f19.tar.bz2 android_packages_apps_Trebuchet-ae6e318711239601fdd11a14c3cf8c542b808f19.zip |
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
Diffstat (limited to 'src/com/android/launcher3')
21 files changed, 604 insertions, 215 deletions
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java index f300ef740..c84be4dac 100644 --- a/src/com/android/launcher3/BaseRecyclerView.java +++ b/src/com/android/launcher3/BaseRecyclerView.java @@ -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; } diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 3611ad47e..8291acc59 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -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); diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 9d9a639d8..fe6bbc08a 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -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 { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6a3a26f77..c0affb944 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -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; diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 4da7907b2..00acdcd2f 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -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(); + } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ddaaa5d08..417c5a29a 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -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"); } diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java index 814002600..20eec05d4 100644 --- a/src/com/android/launcher3/LauncherRootView.java +++ b/src/com/android/launcher3/LauncherRootView.java @@ -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); } diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 30f418d02..1bd82633e 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -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, diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 382eeddf7..26364be06 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -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); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index f1c183bb4..0f4c42d51 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -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; + + RotationMode rotationMode = mLauncher.getRotationMode(); + + rotationMode.mapRect(padding, mTempRect); + setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom); + rotationMode.mapRect(insets, mInsets); - if (grid.shouldFadeAdjacentWorkspaceScreens()) { + 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())); + ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets(); + 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(); diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 99a880104..8d0259d05 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -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); diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index a55ea82c5..70df97ae8 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -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) { diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 6950a1fad..8de2f57ee 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -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); + } + } } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 4dbff1c61..f2eae17da 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -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); } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 02242a3ec..6fa9ba9ae 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -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()); diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index ac908f4ad..46df77a42 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -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; diff --git a/src/com/android/launcher3/graphics/RotationMode.java b/src/com/android/launcher3/graphics/RotationMode.java new file mode 100644 index 000000000..1b2cbdb9f --- /dev/null +++ b/src/com/android/launcher3/graphics/RotationMode.java @@ -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; + } + }; +} diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index c9cdeffb9..0331a86cd 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -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; diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java index 86e1e32a3..3c81bcf39 100644 --- a/src/com/android/launcher3/views/BaseDragLayer.java +++ b/src/com/android/launcher3/views/BaseDragLayer.java @@ -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) { diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 77f278a19..257466539 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -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(); } diff --git a/src/com/android/launcher3/views/Transposable.java b/src/com/android/launcher3/views/Transposable.java new file mode 100644 index 000000000..929c1aa9b --- /dev/null +++ b/src/com/android/launcher3/views/Transposable.java @@ -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(); +} |