mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 00:06:47 +00:00
Merge "Resize preview for correct clipping" into tm-qpr-dev
This commit is contained in:
@@ -38,11 +38,13 @@ import android.util.SparseArray;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.CellLayout.ContainerType;
|
||||
import com.android.launcher3.DevicePaddings.DevicePadding;
|
||||
import com.android.launcher3.icons.DotRenderer;
|
||||
import com.android.launcher3.icons.IconNormalizer;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
@@ -57,6 +59,9 @@ public class DeviceProfile {
|
||||
private static final int DEFAULT_DOT_SIZE = 100;
|
||||
private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f;
|
||||
|
||||
public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
|
||||
public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
|
||||
|
||||
// Ratio of empty space, qsb should take up to appear visually centered.
|
||||
private final float mQsbCenterFactor;
|
||||
|
||||
@@ -204,7 +209,7 @@ public class DeviceProfile {
|
||||
public int overviewGridSideMargin;
|
||||
|
||||
// Widgets
|
||||
public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
|
||||
private final ViewScaleProvider mViewScaleProvider;
|
||||
|
||||
// Drop Target
|
||||
public int dropTargetBarSizePx;
|
||||
@@ -240,7 +245,8 @@ public class DeviceProfile {
|
||||
/** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */
|
||||
DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
|
||||
SparseArray<DotRenderer> dotRendererCache, boolean isMultiWindowMode,
|
||||
boolean transposeLayoutWithOrientation, boolean useTwoPanels, boolean isGestureMode) {
|
||||
boolean transposeLayoutWithOrientation, boolean useTwoPanels, boolean isGestureMode,
|
||||
@NonNull final ViewScaleProvider viewScaleProvider) {
|
||||
|
||||
this.inv = inv;
|
||||
this.isLandscape = windowBounds.isLandscape();
|
||||
@@ -473,6 +479,8 @@ public class DeviceProfile {
|
||||
flingToDeleteThresholdVelocity = res.getDimensionPixelSize(
|
||||
R.dimen.drag_flingToDeleteMinVelocity);
|
||||
|
||||
mViewScaleProvider = viewScaleProvider;
|
||||
|
||||
// This is done last, after iconSizePx is calculated above.
|
||||
mDotRendererWorkSpace = createDotRenderer(iconSizePx, dotRendererCache);
|
||||
mDotRendererAllApps = createDotRenderer(allAppsIconSizePx, dotRendererCache);
|
||||
@@ -669,13 +677,18 @@ public class DeviceProfile {
|
||||
.setMultiWindowMode(true)
|
||||
.build();
|
||||
|
||||
profile.hideWorkspaceLabelsIfNotEnoughSpace();
|
||||
|
||||
// We use these scales to measure and layout the widgets using their full invariant profile
|
||||
// sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
|
||||
float appWidgetScaleX = (float) profile.getCellSize().x / getCellSize().x;
|
||||
float appWidgetScaleY = (float) profile.getCellSize().y / getCellSize().y;
|
||||
profile.appWidgetScale.set(appWidgetScaleX, appWidgetScaleY);
|
||||
if (appWidgetScaleX != 1 || appWidgetScaleY != 1) {
|
||||
final PointF p = new PointF(appWidgetScaleX, appWidgetScaleY);
|
||||
profile = profile.toBuilder(context)
|
||||
.setViewScaleProvider(i -> p)
|
||||
.build();
|
||||
}
|
||||
|
||||
profile.hideWorkspaceLabelsIfNotEnoughSpace();
|
||||
|
||||
return profile;
|
||||
}
|
||||
@@ -1242,6 +1255,19 @@ public class DeviceProfile {
|
||||
+ getOverviewActionsClaimedSpaceBelow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the View and return the scales of width and height depending on the DeviceProfile
|
||||
* specifications
|
||||
*
|
||||
* @param itemInfo The tag of the widget view
|
||||
* @return A PointF instance with the x set to be the scale of width, and y being the scale of
|
||||
* height
|
||||
*/
|
||||
@NonNull
|
||||
public PointF getAppWidgetScale(@Nullable final ItemInfo itemInfo) {
|
||||
return mViewScaleProvider.getScaleFromItemInfo(itemInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bounds for which the open folders should be contained within
|
||||
*/
|
||||
@@ -1551,6 +1577,22 @@ public class DeviceProfile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler that deals with ItemInfo of the views for the DeviceProfile
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ViewScaleProvider {
|
||||
/**
|
||||
* Get the scales from the view
|
||||
*
|
||||
* @param itemInfo The tag of the widget view
|
||||
* @return PointF instance containing the scale information, or null if using the default
|
||||
* app widget scale of this device profile.
|
||||
*/
|
||||
@NonNull
|
||||
PointF getScaleFromItemInfo(@Nullable ItemInfo itemInfo);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Context mContext;
|
||||
private InvariantDeviceProfile mInv;
|
||||
@@ -1562,6 +1604,7 @@ public class DeviceProfile {
|
||||
private boolean mIsMultiWindowMode = false;
|
||||
private Boolean mTransposeLayoutWithOrientation;
|
||||
private Boolean mIsGestureMode;
|
||||
private ViewScaleProvider mViewScaleProvider = null;
|
||||
|
||||
private SparseArray<DotRenderer> mDotRendererCache;
|
||||
|
||||
@@ -1601,6 +1644,19 @@ public class DeviceProfile {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the viewScaleProvider for the builder
|
||||
*
|
||||
* @param viewScaleProvider The viewScaleProvider to be set for the
|
||||
* DeviceProfile
|
||||
* @return This builder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setViewScaleProvider(@Nullable ViewScaleProvider viewScaleProvider) {
|
||||
mViewScaleProvider = viewScaleProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeviceProfile build() {
|
||||
if (mWindowBounds == null) {
|
||||
throw new IllegalArgumentException("Window bounds not set");
|
||||
@@ -1614,9 +1670,12 @@ public class DeviceProfile {
|
||||
if (mDotRendererCache == null) {
|
||||
mDotRendererCache = new SparseArray<>();
|
||||
}
|
||||
if (mViewScaleProvider == null) {
|
||||
mViewScaleProvider = DEFAULT_PROVIDER;
|
||||
}
|
||||
return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds, mDotRendererCache,
|
||||
mIsMultiWindowMode, mTransposeLayoutWithOrientation, mUseTwoPanels,
|
||||
mIsGestureMode);
|
||||
mIsGestureMode, mViewScaleProvider);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import static com.android.launcher3.CellLayout.WORKSPACE;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -32,6 +33,7 @@ import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.CellLayout.ContainerType;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.widget.NavigableAppWidgetHostView;
|
||||
|
||||
@@ -109,8 +111,9 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
if (child instanceof NavigableAppWidgetHostView) {
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
|
||||
final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
profile.appWidgetScale.x, profile.appWidgetScale.y, mBorderSpace, mTempRect);
|
||||
appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect);
|
||||
} else {
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
mBorderSpace, null);
|
||||
@@ -133,8 +136,9 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
|
||||
if (child instanceof NavigableAppWidgetHostView) {
|
||||
((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
|
||||
final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag());
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
dp.appWidgetScale.x, dp.appWidgetScale.y, mBorderSpace, mTempRect);
|
||||
appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect);
|
||||
} else {
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
mBorderSpace, null);
|
||||
@@ -187,8 +191,9 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
|
||||
// Scale and center the widget to fit within its cells.
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
float scaleX = profile.appWidgetScale.x;
|
||||
float scaleY = profile.appWidgetScale.y;
|
||||
final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
|
||||
float scaleX = appWidgetScale.x;
|
||||
float scaleY = appWidgetScale.y;
|
||||
|
||||
nahv.setScaleToFit(Math.min(scaleX, scaleY));
|
||||
nahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
@@ -369,7 +370,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
float scale = 1;
|
||||
if (isWidget) {
|
||||
DeviceProfile profile = mLauncher.getDeviceProfile();
|
||||
scale = Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
final PointF appWidgetScale = profile.getAppWidgetScale(null);
|
||||
scale = Utilities.shrinkRect(r, appWidgetScale.x, appWidgetScale.y);
|
||||
}
|
||||
size[0] = r.width();
|
||||
size[1] = r.height();
|
||||
@@ -2884,7 +2886,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
r.top -= widgetPadding.top;
|
||||
r.bottom += widgetPadding.bottom;
|
||||
}
|
||||
Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
|
||||
PointF appWidgetScale = profile.getAppWidgetScale(null);
|
||||
Utilities.shrinkRect(r, appWidgetScale.x, appWidgetScale.y);
|
||||
}
|
||||
|
||||
mTempFXY[0] = r.left;
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
|
||||
import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
|
||||
@@ -36,6 +37,7 @@ import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
@@ -55,6 +57,7 @@ import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextClock;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
@@ -100,6 +103,7 @@ import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.LocalColorExtractor;
|
||||
import com.android.launcher3.widget.NavigableAppWidgetHostView;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -173,6 +177,7 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
private final Context mContext;
|
||||
private final InvariantDeviceProfile mIdp;
|
||||
private final DeviceProfile mDp;
|
||||
private final DeviceProfile mDpOrig;
|
||||
private final Rect mInsets;
|
||||
private final WorkspaceItemInfo mWorkspaceItemInfo;
|
||||
private final LayoutInflater mHomeElementInflater;
|
||||
@@ -192,7 +197,16 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
mUiHandler = new Handler(Looper.getMainLooper());
|
||||
mContext = context;
|
||||
mIdp = idp;
|
||||
mDp = idp.getDeviceProfile(context).copy(context);
|
||||
mDp = idp.getDeviceProfile(context).toBuilder(context).setViewScaleProvider(
|
||||
this::getAppWidgetScale).build();
|
||||
if (context instanceof PreviewContext) {
|
||||
Context tempContext = ((PreviewContext) context).getBaseContext();
|
||||
mDpOrig = new InvariantDeviceProfile(tempContext, InvariantDeviceProfile
|
||||
.getCurrentGridName(tempContext)).getDeviceProfile(tempContext)
|
||||
.copy(tempContext);
|
||||
} else {
|
||||
mDpOrig = mDp;
|
||||
}
|
||||
|
||||
WindowInsets currentWindowInsets = context.getSystemService(WindowManager.class)
|
||||
.getCurrentWindowMetrics().getWindowInsets();
|
||||
@@ -390,6 +404,41 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
addInScreenFromBind(view, info);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PointF getAppWidgetScale(@Nullable ItemInfo itemInfo) {
|
||||
if (!(itemInfo instanceof LauncherAppWidgetInfo)) {
|
||||
return DEFAULT_SCALE;
|
||||
}
|
||||
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) itemInfo;
|
||||
final Size launcherWidgetSize = mLauncherWidgetSpanInfo.get(info.appWidgetId);
|
||||
if (launcherWidgetSize == null) {
|
||||
return DEFAULT_SCALE;
|
||||
}
|
||||
final Size origSize = WidgetSizes.getWidgetSizePx(mDpOrig,
|
||||
launcherWidgetSize.getWidth(), launcherWidgetSize.getHeight());
|
||||
final Size newSize = WidgetSizes.getWidgetSizePx(mDp, info.spanX, info.spanY);
|
||||
final Rect previewInset = new Rect();
|
||||
final Rect origInset = new Rect();
|
||||
// When the setup() is called for the LayoutParams, insets are added to the width
|
||||
// and height of the view. This is not accounted for in WidgetSizes and is handled
|
||||
// here.
|
||||
if (mDp.shouldInsetWidgets()) {
|
||||
previewInset.set(mDp.inv.defaultWidgetPadding);
|
||||
} else {
|
||||
previewInset.setEmpty();
|
||||
}
|
||||
if (mDpOrig.shouldInsetWidgets()) {
|
||||
origInset.set(mDpOrig.inv.defaultWidgetPadding);
|
||||
} else {
|
||||
origInset.setEmpty();
|
||||
}
|
||||
|
||||
return new PointF((float) newSize.getWidth() / (origSize.getWidth()
|
||||
+ origInset.left + origInset.right),
|
||||
(float) newSize.getHeight() / (origSize.getHeight()
|
||||
+ origInset.top + origInset.bottom));
|
||||
}
|
||||
|
||||
private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
|
||||
CellLayout screen = mWorkspaceScreens.get(info.screenId);
|
||||
View view = PredictedAppIconInflater.inflate(mHomeElementInflater, screen, info);
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.util.SparseArray
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER;
|
||||
import com.android.launcher3.util.DisplayController.Info
|
||||
import com.android.launcher3.util.WindowBounds
|
||||
import org.junit.Before
|
||||
@@ -61,7 +62,8 @@ abstract class DeviceProfileBaseTest {
|
||||
isMultiWindowMode,
|
||||
transposeLayoutWithOrientation,
|
||||
useTwoPanels,
|
||||
isGestureMode
|
||||
isGestureMode,
|
||||
DEFAULT_PROVIDER
|
||||
)
|
||||
|
||||
protected fun initializeVarsForPhone(isGestureMode: Boolean = true,
|
||||
|
||||
Reference in New Issue
Block a user