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

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

Framework changes for go/widget-size-specification

Update the framework to:

1 - Allow creating RemoteViews with a mapping from size to layouts
2 - Use the closes sized layout in any given situation
3 - Allow the launher to specify the current size when inflating a
    remote views

Bug: 179025145
Test: atest android.widget.cts.RemoteViewsSizeMapTest
Change-Id: Icf98d01bd0cf8b48c47555a1af6acb498b46b1a4
parent 44a417e0
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -8294,6 +8294,7 @@ package android.appwidget {
  public class AppWidgetHostView extends android.widget.FrameLayout {
    ctor public AppWidgetHostView(android.content.Context);
    ctor public AppWidgetHostView(android.content.Context, int, int);
    method public void clearCurrentSize();
    method public int getAppWidgetId();
    method public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo();
    method public static android.graphics.Rect getDefaultPaddingForWidget(android.content.Context, android.content.ComponentName, android.graphics.Rect);
@@ -8301,11 +8302,13 @@ package android.appwidget {
    method protected android.view.View getErrorView();
    method protected void prepareView(android.view.View);
    method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
    method public void setCurrentSize(@NonNull android.graphics.PointF);
    method public void setExecutor(java.util.concurrent.Executor);
    method public void setOnLightBackground(boolean);
    method public void updateAppWidget(android.widget.RemoteViews);
    method public void updateAppWidgetOptions(android.os.Bundle);
    method public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
    method @Deprecated public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
    method public void updateAppWidgetSize(@NonNull android.os.Bundle, @NonNull java.util.List<android.graphics.PointF>);
  }
  public class AppWidgetManager {
@@ -8358,6 +8361,7 @@ package android.appwidget {
    field public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
    field public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
    field public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
    field public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes";
  }
  public class AppWidgetProvider extends android.content.BroadcastReceiver {
@@ -54618,6 +54622,7 @@ package android.widget {
  public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
    ctor public RemoteViews(String, int);
    ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
    ctor public RemoteViews(@NonNull java.util.Map<android.graphics.PointF,android.widget.RemoteViews>);
    ctor public RemoteViews(android.widget.RemoteViews);
    ctor public RemoteViews(android.os.Parcel);
    method public void addView(@IdRes int, android.widget.RemoteViews);
+99 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.appwidget;

import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityOptions;
import android.compat.annotation.UnsupportedAppUsage;
@@ -29,6 +30,7 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
@@ -53,6 +55,7 @@ import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

/**
@@ -89,6 +92,7 @@ public class AppWidgetHostView extends FrameLayout {
    int mLayoutId = -1;
    private OnClickHandler mOnClickHandler;
    private boolean mOnLightBackground;
    PointF mCurrentSize = null;

    private Executor mAsyncExecutor;
    private CancellationSignal mLastExecutionSignal;
@@ -268,7 +272,8 @@ public class AppWidgetHostView extends FrameLayout {
     * Provide guidance about the size of this widget to the AppWidgetManager. The widths and
     * heights should correspond to the full area the AppWidgetHostView is given. Padding added by
     * the framework will be accounted for automatically. This information gets embedded into the
     * AppWidget options and causes a callback to the AppWidgetProvider.
     * AppWidget options and causes a callback to the AppWidgetProvider. In addition, the list of
     * sizes is explicitly set to an empty list.
     * @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle)
     *
     * @param newOptions The bundle of options, in addition to the size information,
@@ -277,13 +282,96 @@ public class AppWidgetHostView extends FrameLayout {
     * @param minHeight The maximum height in dips that the widget will be displayed at.
     * @param maxWidth The maximum width in dips that the widget will be displayed at.
     * @param maxHeight The maximum height in dips that the widget will be displayed at.
     *
     * @deprecated use {@link AppWidgetHostView#updateAppWidgetSize(Bundle, List)} instead.
     */
    @Deprecated
    public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
            int maxHeight) {
        updateAppWidgetSize(newOptions, minWidth, minHeight, maxWidth, maxHeight, false);
    }

    /**
     * Provide guidance about the size of this widget to the AppWidgetManager. The sizes should
     * correspond to the full area the AppWidgetHostView is given. Padding added by the framework
     * will be accounted for automatically.
     *
     * This method will update the option bundle with the list of sizes and the min/max bounds for
     * width and height.
     *
     * @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle)
     *
     * @param newOptions The bundle of options, in addition to the size information.
     * @param sizes Sizes, in dips, the widget may be displayed at without calling the provider
     *              again. Typically, this will be size of the widget in landscape and portrait.
     *              On some foldables, this might include the size on the outer and inner screens.
     */
    public void updateAppWidgetSize(@NonNull Bundle newOptions, @NonNull List<PointF> sizes) {
        AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);

        Rect padding = getDefaultPadding();
        float density = getResources().getDisplayMetrics().density;

        float xPaddingDips = (padding.left + padding.right) / density;
        float yPaddingDips = (padding.top + padding.bottom) / density;

        ArrayList<PointF> paddedSizes = new ArrayList<>(sizes.size());
        float minWidth = Float.MAX_VALUE;
        float maxWidth = 0;
        float minHeight = Float.MAX_VALUE;
        float maxHeight = 0;
        for (int i = 0; i < sizes.size(); i++) {
            PointF size = sizes.get(i);
            PointF paddedPoint = new PointF(Math.max(0.f, size.x - xPaddingDips),
                    Math.max(0.f, size.y - yPaddingDips));
            paddedSizes.add(paddedPoint);
            minWidth = Math.min(minWidth, paddedPoint.x);
            maxWidth = Math.max(maxWidth, paddedPoint.x);
            minHeight = Math.min(minHeight, paddedPoint.y);
            maxHeight = Math.max(maxHeight, paddedPoint.y);
        }
        if (paddedSizes.equals(
                widgetManager.getAppWidgetOptions(mAppWidgetId).<PointF>getParcelableArrayList(
                        AppWidgetManager.OPTION_APPWIDGET_SIZES))) {
            return;
        }
        Bundle options = newOptions.deepCopy();
        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, (int) minWidth);
        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, (int) minHeight);
        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, (int) maxWidth);
        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, (int) maxHeight);
        options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, paddedSizes);
        updateAppWidgetOptions(options);
    }

    /**
     * Set the current size of the widget. This should be the full area the AppWidgetHostView is
     * given. Padding added by the framework will be accounted for automatically.
     *
     * This size will be used to choose the appropriate layout the next time the {@link RemoteViews}
     * is re-inflated, if it was created with {@link RemoteViews#RemoteViews(Map)} .
     */
    public void setCurrentSize(@NonNull PointF size) {
        Rect padding = getDefaultPadding();
        float density = getResources().getDisplayMetrics().density;
        float xPaddingDips = (padding.left + padding.right) / density;
        float yPaddingDips = (padding.top + padding.bottom) / density;
        PointF newSize = new PointF(size.x - xPaddingDips, size.y - yPaddingDips);
        if (!newSize.equals(mCurrentSize)) {
            mCurrentSize = newSize;
            mLayoutId = -1; // Prevents recycling the view.
        }
    }

    /**
     * Clear the current size, indicating it is not currently known.
     */
    public void clearCurrentSize() {
        if (mCurrentSize != null) {
            mCurrentSize = null;
            mLayoutId = -1;
        }
    }

    /**
     * @hide
     */
@@ -322,6 +410,8 @@ public class AppWidgetHostView extends FrameLayout {
            newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, newMinHeight);
            newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, newMaxWidth);
            newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, newMaxHeight);
            newOptions.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES,
                    new ArrayList<PointF>());
            updateAppWidgetOptions(newOptions);
        }
    }
@@ -440,7 +530,7 @@ public class AppWidgetHostView extends FrameLayout {
            // Try normal RemoteView inflation
            if (content == null) {
                try {
                    content = remoteViews.apply(mContext, this, mOnClickHandler);
                    content = remoteViews.apply(mContext, this, mOnClickHandler, mCurrentSize);
                    if (LOGD) Log.d(TAG, "had to inflate new layout");
                } catch (RuntimeException e) {
                    exception = e;
@@ -492,7 +582,8 @@ public class AppWidgetHostView extends FrameLayout {
                        mView,
                        mAsyncExecutor,
                        new ViewApplyListener(remoteViews, layoutId, true),
                        mOnClickHandler);
                        mOnClickHandler,
                        mCurrentSize);
            } catch (Exception e) {
                // Reapply failed. Try apply
            }
@@ -502,7 +593,8 @@ public class AppWidgetHostView extends FrameLayout {
                    this,
                    mAsyncExecutor,
                    new ViewApplyListener(remoteViews, layoutId, false),
                    mOnClickHandler);
                    mOnClickHandler,
                    mCurrentSize);
        }
    }

@@ -533,7 +625,8 @@ public class AppWidgetHostView extends FrameLayout {
                        AppWidgetHostView.this,
                        mAsyncExecutor,
                        new ViewApplyListener(mViews, mLayoutId, false),
                        mOnClickHandler);
                        mOnClickHandler,
                        mCurrentSize);
            } else {
                applyContent(null, false, e);
            }
+6 −0
Original line number Diff line number Diff line
@@ -216,6 +216,12 @@ public class AppWidgetManager {
     */
    public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";

    /**
     * A bundle extra ({@code List<PointF>}) that contains the list of possible sizes, in dips, a
     * widget instance can take.
     */
    public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes";

    /**
     * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
     * this widget. Can have the value {@link
+308 −33

File changed.

Preview size limit exceeded, changes collapsed.