Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2526feb authored by Pierre Barbier de Reuille's avatar Pierre Barbier de Reuille
Browse files

Launcher changes for go/widget-size-specification

Makes sure the launcher:

1 - Send the list of actual sizes the widget in all situations.
2 - Gives the current size to the framework on inflation.

Also needed to guard the new border changes introduced in
http://ag/13532637 with the corresponding flag.

Change-Id: I2a33e9501b921f2fc393684e8ce91ee077626bf7
Test: By hand using a local widget.
Bug: 179025145
parent c7d72e55
Loading
Loading
Loading
Loading
+93 −20
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ package com.android.launcher3;

import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
import static com.android.launcher3.Utilities.ATLEAST_S;
import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS;
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;

@@ -11,14 +13,19 @@ import android.animation.PropertyValuesHolder;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;

import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.FocusLogic;
@@ -353,32 +360,98 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O

    public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
                                              int spanX, int spanY) {
        getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
        widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
                sTmpRect.right, sTmpRect.bottom);
        List<PointF> sizes = getWidgetSizes(launcher, spanX, spanY);
        if (ATLEAST_S) {
            widgetView.updateAppWidgetSize(new Bundle(), sizes);
        } else {
            Rect bounds = getMinMaxSizes(sizes, null /* outRect */);
            widgetView.updateAppWidgetSize(new Bundle(), bounds.left, bounds.top, bounds.right,
                    bounds.bottom);
        }

    public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, Rect rect) {
        if (rect == null) {
            rect = new Rect();
    }
        final float density = context.getResources().getDisplayMetrics().density;
        final Point[] cellSize = CELL_SIZE.get(context);

    private static PointF getWidgetSize(Context context, Point cellSize, int spanX, int spanY) {
        final float density = context.getResources().getDisplayMetrics().density;
        float hBorderSpacing = 0;
        float vBorderSpacing = 0;
        if (ENABLE_FOUR_COLUMNS.get()) {
            final int borderSpacing = context.getResources()
                    .getDimensionPixelSize(R.dimen.dynamic_grid_cell_border_spacing);
        final float hBorderSpacing = (spanX - 1) * borderSpacing;
        final float vBorderSpacing = (spanY - 1) * borderSpacing;

        // Compute landscape size
        int landWidth = (int) (((spanX * cellSize[0].x) + hBorderSpacing) / density);
        int landHeight = (int) (((spanY * cellSize[0].y) + vBorderSpacing) / density);

        // Compute portrait size
        int portWidth = (int) (((spanX * cellSize[1].x) + hBorderSpacing) / density);
        int portHeight = (int) (((spanY * cellSize[1].y) + vBorderSpacing) / density);
        rect.set(portWidth, landHeight, landWidth, portHeight);
        return rect;
            hBorderSpacing = (spanX - 1) * borderSpacing;
            vBorderSpacing = (spanY - 1) * borderSpacing;
        }
        PointF widgetSize = new PointF();
        widgetSize.x = ((spanX * cellSize.x) + hBorderSpacing) / density;
        widgetSize.y = ((spanY * cellSize.y) + vBorderSpacing) / density;
        return widgetSize;
    }

    /** Returns the actual widget size given its span. */
    public static PointF getWidgetSize(Context context, int spanX, int spanY) {
        final Point[] cellSize = CELL_SIZE.get(context);
        if (isLandscape(context)) {
            return getWidgetSize(context, cellSize[0], spanX, spanY);
        }
        return getWidgetSize(context, cellSize[1], spanX, spanY);
    }

    /** Returns true if the screen is in landscape mode. */
    private static boolean isLandscape(Context context) {
        return context.getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE;
    }

    /** Returns the list of sizes for a widget of given span, in dp. */
    public static ArrayList<PointF> getWidgetSizes(Context context, int spanX, int spanY) {
        final Point[] cellSize = CELL_SIZE.get(context);

        PointF landSize = getWidgetSize(context, cellSize[0], spanX, spanY);
        PointF portSize = getWidgetSize(context, cellSize[1], spanX, spanY);

        ArrayList<PointF> sizes = new ArrayList<>(2);
        sizes.add(landSize);
        sizes.add(portSize);
        return sizes;
    }

    /**
     * Returns the min and max widths and heights given a list of sizes, in dp.
     *
     * @param sizes List of sizes to get the min/max from.
     * @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If
     *               null, a new rectangle will be allocated.
     * @return A rectangle with the left (resp. top) is used for the min width (resp. height) and
     * the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is
     * empty.
     */
    public static Rect getMinMaxSizes(List<PointF> sizes, @Nullable Rect outRect) {
        if (outRect == null) {
            outRect = new Rect();
        }
        if (sizes.isEmpty()) {
            outRect.set(0, 0, 0, 0);
        } else {
            PointF first = sizes.get(0);
            outRect.set((int) first.x, (int) first.y, (int) first.x, (int) first.y);
            for (int i = 1; i < sizes.size(); i++) {
                outRect.union((int) sizes.get(i).x, (int) sizes.get(i).y);
            }
        }
        return outRect;
    }

    /**
     * Returns the range of sizes a widget may be displayed, given its span.
     *
     * @param context Context in which the View is rendered.
     * @param spanX Width of the widget, in cells.
     * @param spanY Height of the widget, in cells.
     * @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If
     *               null, a new rectangle will be allocated.
     */
    public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY,
            @Nullable Rect outRect) {
        return getMinMaxSizes(getWidgetSizes(context, spanX, spanY), outRect);
    }

    @Override
+2 −4
Original line number Diff line number Diff line
@@ -357,10 +357,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
        }

        layout.markCellsAsOccupiedForView(host);
        Rect sizeRange = new Rect();
        AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, sizeRange);
        ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null,
                sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom);
        AppWidgetResizeFrame.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mLauncher,
                info.spanX, info.spanY);
        host.requestLayout();
        mLauncher.getModelWriter().updateItemInDatabase(info);
        announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY));
+11 −2
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_BIND;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;

import static com.android.launcher3.Utilities.ATLEAST_S;

import android.app.Activity;
import android.app.Fragment;
import android.app.SearchManager;
@@ -30,6 +32,7 @@ import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.Settings;
@@ -50,6 +53,8 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.FragmentWithPreview;

import java.util.ArrayList;

/**
 * A frame layout which contains a QSB. This internally uses fragment to bind the view, which
 * allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
@@ -294,12 +299,16 @@ public class QsbContainerView extends FrameLayout {
            InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());

            Bundle opts = new Bundle();
            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(getContext(),
                    idp.numColumns, 1, null);
            ArrayList<PointF> sizes = AppWidgetResizeFrame
                    .getWidgetSizes(getContext(), idp.numColumns, 1);
            Rect size = AppWidgetResizeFrame.getMinMaxSizes(sizes, null /* outRect */);
            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
            if (ATLEAST_S) {
                opts.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes);
            }
            return opts;
        }

+13 −2
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.launcher3.widget;

import static com.android.launcher3.Utilities.ATLEAST_S;

import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PointF;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
@@ -70,8 +73,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
    private boolean mIsAutoAdvanceRegistered;
    private Runnable mAutoAdvanceRunnable;



    public LauncherAppWidgetHostView(Context context) {
        super(context);
        mLauncher = Launcher.getLauncher(context);
@@ -218,6 +219,16 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
        mIsScrollable = checkScrollableRecursively(this);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        if (ATLEAST_S) {
            float density = getContext().getResources().getDisplayMetrics().density;
            setCurrentSize(new PointF(w / density, h / density));
        }
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
+8 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -46,6 +47,8 @@ import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;

import java.util.List;

public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
        implements OnClickListener, ItemInfoUpdateReceiver {
    private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
@@ -108,6 +111,11 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
        // No-op
    }

    @Override
    public void updateAppWidgetSize(Bundle newOptions, List<PointF> sizes) {
        // No-op
    }

    @Override
    protected View getDefaultView() {
        View defaultView = mInflater.inflate(R.layout.appwidget_not_ready, this, false);
Loading