Loading core/api/current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -8372,7 +8372,6 @@ 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); Loading @@ -8382,13 +8381,12 @@ package android.appwidget { method public void resetColorResources(); method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo); method public void setColorResources(@NonNull android.util.SparseIntArray); 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 @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>); method public void updateAppWidgetSize(@NonNull android.os.Bundle, @NonNull java.util.List<android.util.SizeF>); } public class AppWidgetManager { Loading Loading @@ -45948,11 +45946,14 @@ package android.util { method public static android.util.Size parseSize(String) throws java.lang.NumberFormatException; } public final class SizeF { public final class SizeF implements android.os.Parcelable { ctor public SizeF(float, float); method public int describeContents(); method public float getHeight(); method public float getWidth(); method public static android.util.SizeF parseSizeF(String) throws java.lang.NumberFormatException; method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.util.SizeF> CREATOR; } public class SparseArray<E> implements java.lang.Cloneable { Loading Loading @@ -54844,7 +54845,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(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>); ctor public RemoteViews(android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); method public void addView(@IdRes int, android.widget.RemoteViews); core/java/android/appwidget/AppWidgetHostView.java +43 −49 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; import android.util.SizeF; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Gravity; Loading @@ -56,7 +57,6 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; /** Loading Loading @@ -93,7 +93,7 @@ public class AppWidgetHostView extends FrameLayout { int mLayoutId = -1; private InteractionHandler mInteractionHandler; private boolean mOnLightBackground; private PointF mCurrentSize = null; private SizeF mCurrentSize = null; private RemoteViews.ColorResources mColorResources = null; // Stores the last remote views last inflated. private RemoteViews mLastInflatedRemoteViews = null; Loading Loading @@ -253,9 +253,33 @@ public class AppWidgetHostView extends FrameLayout { } } private SizeF computeSizeFromLayout(int left, int top, int right, int bottom) { Rect padding = getDefaultPadding(); float density = getResources().getDisplayMetrics().density; return new SizeF( (right - left - padding.right - padding.left) / density, (bottom - top - padding.bottom - padding.top) / density ); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { try { SizeF oldSize = mCurrentSize; SizeF newSize = computeSizeFromLayout(left, top, right, bottom); mCurrentSize = newSize; if (mLastInflatedRemoteViews != null) { RemoteViews toApply = mLastInflatedRemoteViews.getRemoteViewsToApplyIfDifferent( oldSize, newSize); if (toApply != null) { applyRemoteViews(toApply, false); measureChildWithMargins(mView, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), 0 /* widthUsed */, MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY), 0 /* heightUsed */); } } super.onLayout(changed, left, top, right, bottom); } catch (final RuntimeException e) { Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e); Loading Loading @@ -309,7 +333,7 @@ public class AppWidgetHostView extends FrameLayout { * 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) { public void updateAppWidgetSize(@NonNull Bundle newOptions, @NonNull List<SizeF> sizes) { AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext); Rect padding = getDefaultPadding(); Loading @@ -318,20 +342,20 @@ public class AppWidgetHostView extends FrameLayout { float xPaddingDips = (padding.left + padding.right) / density; float yPaddingDips = (padding.top + padding.bottom) / density; ArrayList<PointF> paddedSizes = new ArrayList<>(sizes.size()); ArrayList<SizeF> 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); SizeF size = sizes.get(i); SizeF paddedSize = new SizeF(Math.max(0.f, size.getWidth() - xPaddingDips), Math.max(0.f, size.getHeight() - yPaddingDips)); paddedSizes.add(paddedSize); minWidth = Math.min(minWidth, paddedSize.getWidth()); maxWidth = Math.max(maxWidth, paddedSize.getWidth()); minHeight = Math.min(minHeight, paddedSize.getHeight()); maxHeight = Math.max(maxHeight, paddedSize.getHeight()); } if (paddedSizes.equals( widgetManager.getAppWidgetOptions(mAppWidgetId).<PointF>getParcelableArrayList( Loading @@ -347,35 +371,6 @@ public class AppWidgetHostView extends FrameLayout { 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; reapplyLastRemoteViews(); } } /** * Clear the current size, indicating it is not currently known. */ public void clearCurrentSize() { if (mCurrentSize != null) { mCurrentSize = null; reapplyLastRemoteViews(); } } /** * @hide */ Loading Loading @@ -514,23 +509,22 @@ public class AppWidgetHostView extends FrameLayout { mLayoutId = -1; mViewMode = VIEW_MODE_DEFAULT; } else { // Select the remote view we are actually going to apply. RemoteViews rvToApply = remoteViews.getRemoteViewsToApply(mContext, mCurrentSize); if (mOnLightBackground) { remoteViews = remoteViews.getDarkTextViews(); rvToApply = rvToApply.getDarkTextViews(); } if (mAsyncExecutor != null && useAsyncIfPossible) { inflateAsync(remoteViews); inflateAsync(rvToApply); return; } // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. mRemoteContext = getRemoteContext(); int layoutId = remoteViews.getLayoutId(); int layoutId = rvToApply.getLayoutId(); // If our stale view has been prepared to match active, and the new // layout matches, try recycling it if (content == null && layoutId == mLayoutId) { try { remoteViews.reapply(mContext, mView, mInteractionHandler, mCurrentSize, rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize, mColorResources); content = mView; recycled = true; Loading @@ -543,7 +537,7 @@ public class AppWidgetHostView extends FrameLayout { // Try normal RemoteView inflation if (content == null) { try { content = remoteViews.apply(mContext, this, mInteractionHandler, content = rvToApply.apply(mContext, this, mInteractionHandler, mCurrentSize, mColorResources); if (LOGD) Log.d(TAG, "had to inflate new layout"); } catch (RuntimeException e) { Loading core/java/android/appwidget/AppWidgetManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -219,7 +219,7 @@ 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 * A bundle extra ({@code List<SizeF>}) that contains the list of possible sizes, in dips, a * widget instance can take. */ public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes"; Loading core/java/android/util/SizeF.java +45 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package android.util; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkArgumentFinite; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; /** * Immutable class for describing width and height dimensions in some arbitrary Loading @@ -26,7 +30,7 @@ import static com.android.internal.util.Preconditions.checkArgumentFinite; * Width and height are finite values stored as a floating point representation. * </p> */ public final class SizeF { public final class SizeF implements Parcelable { /** * Create a new immutable SizeF instance. * Loading Loading @@ -161,4 +165,43 @@ public final class SizeF { private final float mWidth; private final float mHeight; /** * Parcelable interface methods */ @Override public int describeContents() { return 0; } /** * Write this size to the specified parcel. To restore a size from a parcel, use the * {@link #CREATOR}. * @param out The parcel to write the point's coordinates into */ @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeFloat(mWidth); out.writeFloat(mHeight); } public static final @NonNull Creator<SizeF> CREATOR = new Creator<SizeF>() { /** * Return a new size from the data in the specified parcel. */ @Override public @NonNull SizeF createFromParcel(@NonNull Parcel in) { float width = in.readFloat(); float height = in.readFloat(); return new SizeF(width, height); } /** * Return an array of sizes of the specified size. */ @Override public @NonNull SizeF[] newArray(int size) { return new SizeF[size]; } }; } core/java/android/widget/RemoteViews.java +70 −39 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ import android.content.res.loader.ResourcesProvider; import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Outline; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; Loading @@ -76,6 +75,7 @@ import android.util.DisplayMetrics; import android.util.IntArray; import android.util.Log; import android.util.Pair; import android.util.SizeF; import android.util.SparseIntArray; import android.util.TypedValue; import android.util.TypedValue.ComplexDimensionUnit; Loading Loading @@ -353,7 +353,7 @@ public class RemoteViews implements Parcelable, Filter { * Only to be used on children views used in a {@link RemoteViews} with * {@link RemoteViews#hasSizedRemoteViews()}. */ private PointF mIdealSize = null; private SizeF mIdealSize = null; @ApplyFlags private int mApplyFlags = 0; Loading Loading @@ -3042,11 +3042,11 @@ public class RemoteViews implements Parcelable, Filter { return mSizedRemoteViews != null; } private @Nullable PointF getIdealSize() { private @Nullable SizeF getIdealSize() { return mIdealSize; } private void setIdealSize(@Nullable PointF size) { private void setIdealSize(@Nullable SizeF size) { mIdealSize = size; } Loading Loading @@ -3094,13 +3094,18 @@ public class RemoteViews implements Parcelable, Filter { * Create a new RemoteViews object that will inflate the layout with the closest size * specification. * * The default remote views in that case is always the smallest one provided. * The default remote views in that case is always the one with the smallest area. * * If the {@link RemoteViews} host provides the size of the view, the layout with the largest * area that fits entirely in the provided size will be used (i.e. the width and height of * the layout must be less than the size of the view, with a 1dp margin to account for * rounding). If no layout fits in the view, the layout with the smallest area will be used. * * @param remoteViews Mapping of size to layout. * @throws IllegalArgumentException if the map is empty, there are more than * MAX_INIT_VIEW_COUNT layouts or the remote views are not all from the same application. */ public RemoteViews(@NonNull Map<PointF, RemoteViews> remoteViews) { public RemoteViews(@NonNull Map<SizeF, RemoteViews> remoteViews) { if (remoteViews.isEmpty()) { throw new IllegalArgumentException("The set of RemoteViews cannot be empty"); } Loading Loading @@ -3135,8 +3140,8 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews smallestView = null; while (remoteViews.hasNext()) { RemoteViews view = remoteViews.next(); PointF size = view.getIdealSize(); float newViewArea = size.x * size.y; SizeF size = view.getIdealSize(); float newViewArea = size.getWidth() * size.getHeight(); if (smallestView != null && !view.hasSameAppInfo(smallestView.mApplication)) { throw new IllegalArgumentException( "All RemoteViews must share the same package and user"); Loading Loading @@ -3239,7 +3244,7 @@ public class RemoteViews implements Parcelable, Filter { if (mode == MODE_NORMAL) { mApplication = parcel.readInt() == 0 ? info : ApplicationInfo.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : PointF.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel); mLayoutId = parcel.readInt(); mLightBackgroundLayoutId = parcel.readInt(); Loading Loading @@ -4625,9 +4630,9 @@ public class RemoteViews implements Parcelable, Filter { * * This is particularly useful when we only care about the ordering of the distances. */ private static float squareDistance(PointF p1, PointF p2) { float dx = p1.x - p2.x; float dy = p1.y - p2.y; private static float squareDistance(SizeF p1, SizeF p2) { float dx = p1.getWidth() - p2.getWidth(); float dy = p1.getHeight() - p2.getHeight(); return dx * dx + dy * dy; } Loading @@ -4637,31 +4642,17 @@ public class RemoteViews implements Parcelable, Filter { * A layout fits on a widget if the widget size is known (i.e. not null) and both dimensions * are smaller than the ones of the widget, adding some padding to account for rounding errors. */ private static boolean fitsIn(PointF sizeLayout, @Nullable PointF sizeWidget) { return sizeWidget != null && (Math.ceil(sizeWidget.x) + 1 > sizeLayout.x) && (Math.ceil(sizeWidget.y) + 1 > sizeLayout.y); private static boolean fitsIn(SizeF sizeLayout, @Nullable SizeF sizeWidget) { return sizeWidget != null && (Math.ceil(sizeWidget.getWidth()) + 1 > sizeLayout.getWidth()) && (Math.ceil(sizeWidget.getHeight()) + 1 > sizeLayout.getHeight()); } /** * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the * size of the widget. * * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the * diagonal the most similar to the widget. If no layout fits or the size of the widget is * not specified, the one with the smallest area will be chosen. */ private RemoteViews getRemoteViewsToApply(@NonNull Context context, @Nullable PointF widgetSize) { if (!hasSizedRemoteViews()) { // If there isn't multiple remote views, fall back on the previous methods. return getRemoteViewsToApply(context); } private RemoteViews findBestFitLayout(@NonNull SizeF widgetSize) { // Find the better remote view RemoteViews bestFit = null; float bestSqDist = Float.MAX_VALUE; for (RemoteViews layout : mSizedRemoteViews) { PointF layoutSize = layout.getIdealSize(); SizeF layoutSize = layout.getIdealSize(); if (fitsIn(layoutSize, widgetSize)) { if (bestFit == null) { bestFit = layout; Loading @@ -4682,6 +4673,46 @@ public class RemoteViews implements Parcelable, Filter { return bestFit; } /** * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the * size of the widget. * * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the * diagonal the most similar to the widget. If no layout fits or the size of the widget is * not specified, the one with the smallest area will be chosen. * * @hide */ public RemoteViews getRemoteViewsToApply(@NonNull Context context, @Nullable SizeF widgetSize) { if (!hasSizedRemoteViews()) { // If there isn't multiple remote views, fall back on the previous methods. return getRemoteViewsToApply(context); } return findBestFitLayout(widgetSize); } /** * Checks whether the change of size will lead to using a different {@link RemoteViews}. * * @hide */ @Nullable public RemoteViews getRemoteViewsToApplyIfDifferent(@Nullable SizeF oldSize, @NonNull SizeF newSize) { if (!hasSizedRemoteViews()) { return null; } RemoteViews oldBestFit = oldSize == null ? findSmallestRemoteView() : findBestFitLayout( oldSize); RemoteViews newBestFit = findBestFitLayout(newSize); if (oldBestFit != newBestFit) { return newBestFit; } return null; } /** * Inflates the view hierarchy represented by this object and applies Loading @@ -4705,7 +4736,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View apply(@NonNull Context context, @NonNull ViewGroup parent, @Nullable InteractionHandler handler, @Nullable PointF size) { @Nullable InteractionHandler handler, @Nullable SizeF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent); Loading @@ -4722,7 +4753,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent, @Nullable InteractionHandler handler, @StyleRes int applyThemeResId, @Nullable PointF size) { @Nullable SizeF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent, applyThemeResId, null); Loading @@ -4732,7 +4763,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View apply(Context context, ViewGroup parent, InteractionHandler handler, @NonNull PointF size, @Nullable ColorResources colorResources) { @NonNull SizeF size, @Nullable ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent, 0, colorResources); Loading Loading @@ -4828,21 +4859,21 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size) { SizeF size) { return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */) .startTaskOnExecutor(executor); } /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { return getAsyncApplyTask(context, parent, listener, handler, size, colorResources) .startTaskOnExecutor(executor); } private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener, handler, colorResources, null /* result */); Loading Loading @@ -4968,7 +4999,7 @@ public class RemoteViews implements Parcelable, Filter { } /** @hide */ public void reapply(Context context, View v, InteractionHandler handler, PointF size, public void reapply(Context context, View v, InteractionHandler handler, SizeF size, ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); Loading Loading @@ -5012,7 +5043,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public CancellationSignal reapplyAsync(Context context, View v, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); Loading Loading
core/api/current.txt +6 −5 Original line number Diff line number Diff line Loading @@ -8372,7 +8372,6 @@ 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); Loading @@ -8382,13 +8381,12 @@ package android.appwidget { method public void resetColorResources(); method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo); method public void setColorResources(@NonNull android.util.SparseIntArray); 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 @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>); method public void updateAppWidgetSize(@NonNull android.os.Bundle, @NonNull java.util.List<android.util.SizeF>); } public class AppWidgetManager { Loading Loading @@ -45948,11 +45946,14 @@ package android.util { method public static android.util.Size parseSize(String) throws java.lang.NumberFormatException; } public final class SizeF { public final class SizeF implements android.os.Parcelable { ctor public SizeF(float, float); method public int describeContents(); method public float getHeight(); method public float getWidth(); method public static android.util.SizeF parseSizeF(String) throws java.lang.NumberFormatException; method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.util.SizeF> CREATOR; } public class SparseArray<E> implements java.lang.Cloneable { Loading Loading @@ -54844,7 +54845,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(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>); ctor public RemoteViews(android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); method public void addView(@IdRes int, android.widget.RemoteViews);
core/java/android/appwidget/AppWidgetHostView.java +43 −49 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; import android.util.SizeF; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Gravity; Loading @@ -56,7 +57,6 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; /** Loading Loading @@ -93,7 +93,7 @@ public class AppWidgetHostView extends FrameLayout { int mLayoutId = -1; private InteractionHandler mInteractionHandler; private boolean mOnLightBackground; private PointF mCurrentSize = null; private SizeF mCurrentSize = null; private RemoteViews.ColorResources mColorResources = null; // Stores the last remote views last inflated. private RemoteViews mLastInflatedRemoteViews = null; Loading Loading @@ -253,9 +253,33 @@ public class AppWidgetHostView extends FrameLayout { } } private SizeF computeSizeFromLayout(int left, int top, int right, int bottom) { Rect padding = getDefaultPadding(); float density = getResources().getDisplayMetrics().density; return new SizeF( (right - left - padding.right - padding.left) / density, (bottom - top - padding.bottom - padding.top) / density ); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { try { SizeF oldSize = mCurrentSize; SizeF newSize = computeSizeFromLayout(left, top, right, bottom); mCurrentSize = newSize; if (mLastInflatedRemoteViews != null) { RemoteViews toApply = mLastInflatedRemoteViews.getRemoteViewsToApplyIfDifferent( oldSize, newSize); if (toApply != null) { applyRemoteViews(toApply, false); measureChildWithMargins(mView, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), 0 /* widthUsed */, MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY), 0 /* heightUsed */); } } super.onLayout(changed, left, top, right, bottom); } catch (final RuntimeException e) { Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e); Loading Loading @@ -309,7 +333,7 @@ public class AppWidgetHostView extends FrameLayout { * 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) { public void updateAppWidgetSize(@NonNull Bundle newOptions, @NonNull List<SizeF> sizes) { AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext); Rect padding = getDefaultPadding(); Loading @@ -318,20 +342,20 @@ public class AppWidgetHostView extends FrameLayout { float xPaddingDips = (padding.left + padding.right) / density; float yPaddingDips = (padding.top + padding.bottom) / density; ArrayList<PointF> paddedSizes = new ArrayList<>(sizes.size()); ArrayList<SizeF> 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); SizeF size = sizes.get(i); SizeF paddedSize = new SizeF(Math.max(0.f, size.getWidth() - xPaddingDips), Math.max(0.f, size.getHeight() - yPaddingDips)); paddedSizes.add(paddedSize); minWidth = Math.min(minWidth, paddedSize.getWidth()); maxWidth = Math.max(maxWidth, paddedSize.getWidth()); minHeight = Math.min(minHeight, paddedSize.getHeight()); maxHeight = Math.max(maxHeight, paddedSize.getHeight()); } if (paddedSizes.equals( widgetManager.getAppWidgetOptions(mAppWidgetId).<PointF>getParcelableArrayList( Loading @@ -347,35 +371,6 @@ public class AppWidgetHostView extends FrameLayout { 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; reapplyLastRemoteViews(); } } /** * Clear the current size, indicating it is not currently known. */ public void clearCurrentSize() { if (mCurrentSize != null) { mCurrentSize = null; reapplyLastRemoteViews(); } } /** * @hide */ Loading Loading @@ -514,23 +509,22 @@ public class AppWidgetHostView extends FrameLayout { mLayoutId = -1; mViewMode = VIEW_MODE_DEFAULT; } else { // Select the remote view we are actually going to apply. RemoteViews rvToApply = remoteViews.getRemoteViewsToApply(mContext, mCurrentSize); if (mOnLightBackground) { remoteViews = remoteViews.getDarkTextViews(); rvToApply = rvToApply.getDarkTextViews(); } if (mAsyncExecutor != null && useAsyncIfPossible) { inflateAsync(remoteViews); inflateAsync(rvToApply); return; } // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. mRemoteContext = getRemoteContext(); int layoutId = remoteViews.getLayoutId(); int layoutId = rvToApply.getLayoutId(); // If our stale view has been prepared to match active, and the new // layout matches, try recycling it if (content == null && layoutId == mLayoutId) { try { remoteViews.reapply(mContext, mView, mInteractionHandler, mCurrentSize, rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize, mColorResources); content = mView; recycled = true; Loading @@ -543,7 +537,7 @@ public class AppWidgetHostView extends FrameLayout { // Try normal RemoteView inflation if (content == null) { try { content = remoteViews.apply(mContext, this, mInteractionHandler, content = rvToApply.apply(mContext, this, mInteractionHandler, mCurrentSize, mColorResources); if (LOGD) Log.d(TAG, "had to inflate new layout"); } catch (RuntimeException e) { Loading
core/java/android/appwidget/AppWidgetManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -219,7 +219,7 @@ 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 * A bundle extra ({@code List<SizeF>}) that contains the list of possible sizes, in dips, a * widget instance can take. */ public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes"; Loading
core/java/android/util/SizeF.java +45 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,12 @@ package android.util; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkArgumentFinite; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; /** * Immutable class for describing width and height dimensions in some arbitrary Loading @@ -26,7 +30,7 @@ import static com.android.internal.util.Preconditions.checkArgumentFinite; * Width and height are finite values stored as a floating point representation. * </p> */ public final class SizeF { public final class SizeF implements Parcelable { /** * Create a new immutable SizeF instance. * Loading Loading @@ -161,4 +165,43 @@ public final class SizeF { private final float mWidth; private final float mHeight; /** * Parcelable interface methods */ @Override public int describeContents() { return 0; } /** * Write this size to the specified parcel. To restore a size from a parcel, use the * {@link #CREATOR}. * @param out The parcel to write the point's coordinates into */ @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeFloat(mWidth); out.writeFloat(mHeight); } public static final @NonNull Creator<SizeF> CREATOR = new Creator<SizeF>() { /** * Return a new size from the data in the specified parcel. */ @Override public @NonNull SizeF createFromParcel(@NonNull Parcel in) { float width = in.readFloat(); float height = in.readFloat(); return new SizeF(width, height); } /** * Return an array of sizes of the specified size. */ @Override public @NonNull SizeF[] newArray(int size) { return new SizeF[size]; } }; }
core/java/android/widget/RemoteViews.java +70 −39 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ import android.content.res.loader.ResourcesProvider; import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Outline; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; Loading @@ -76,6 +75,7 @@ import android.util.DisplayMetrics; import android.util.IntArray; import android.util.Log; import android.util.Pair; import android.util.SizeF; import android.util.SparseIntArray; import android.util.TypedValue; import android.util.TypedValue.ComplexDimensionUnit; Loading Loading @@ -353,7 +353,7 @@ public class RemoteViews implements Parcelable, Filter { * Only to be used on children views used in a {@link RemoteViews} with * {@link RemoteViews#hasSizedRemoteViews()}. */ private PointF mIdealSize = null; private SizeF mIdealSize = null; @ApplyFlags private int mApplyFlags = 0; Loading Loading @@ -3042,11 +3042,11 @@ public class RemoteViews implements Parcelable, Filter { return mSizedRemoteViews != null; } private @Nullable PointF getIdealSize() { private @Nullable SizeF getIdealSize() { return mIdealSize; } private void setIdealSize(@Nullable PointF size) { private void setIdealSize(@Nullable SizeF size) { mIdealSize = size; } Loading Loading @@ -3094,13 +3094,18 @@ public class RemoteViews implements Parcelable, Filter { * Create a new RemoteViews object that will inflate the layout with the closest size * specification. * * The default remote views in that case is always the smallest one provided. * The default remote views in that case is always the one with the smallest area. * * If the {@link RemoteViews} host provides the size of the view, the layout with the largest * area that fits entirely in the provided size will be used (i.e. the width and height of * the layout must be less than the size of the view, with a 1dp margin to account for * rounding). If no layout fits in the view, the layout with the smallest area will be used. * * @param remoteViews Mapping of size to layout. * @throws IllegalArgumentException if the map is empty, there are more than * MAX_INIT_VIEW_COUNT layouts or the remote views are not all from the same application. */ public RemoteViews(@NonNull Map<PointF, RemoteViews> remoteViews) { public RemoteViews(@NonNull Map<SizeF, RemoteViews> remoteViews) { if (remoteViews.isEmpty()) { throw new IllegalArgumentException("The set of RemoteViews cannot be empty"); } Loading Loading @@ -3135,8 +3140,8 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews smallestView = null; while (remoteViews.hasNext()) { RemoteViews view = remoteViews.next(); PointF size = view.getIdealSize(); float newViewArea = size.x * size.y; SizeF size = view.getIdealSize(); float newViewArea = size.getWidth() * size.getHeight(); if (smallestView != null && !view.hasSameAppInfo(smallestView.mApplication)) { throw new IllegalArgumentException( "All RemoteViews must share the same package and user"); Loading Loading @@ -3239,7 +3244,7 @@ public class RemoteViews implements Parcelable, Filter { if (mode == MODE_NORMAL) { mApplication = parcel.readInt() == 0 ? info : ApplicationInfo.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : PointF.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel); mLayoutId = parcel.readInt(); mLightBackgroundLayoutId = parcel.readInt(); Loading Loading @@ -4625,9 +4630,9 @@ public class RemoteViews implements Parcelable, Filter { * * This is particularly useful when we only care about the ordering of the distances. */ private static float squareDistance(PointF p1, PointF p2) { float dx = p1.x - p2.x; float dy = p1.y - p2.y; private static float squareDistance(SizeF p1, SizeF p2) { float dx = p1.getWidth() - p2.getWidth(); float dy = p1.getHeight() - p2.getHeight(); return dx * dx + dy * dy; } Loading @@ -4637,31 +4642,17 @@ public class RemoteViews implements Parcelable, Filter { * A layout fits on a widget if the widget size is known (i.e. not null) and both dimensions * are smaller than the ones of the widget, adding some padding to account for rounding errors. */ private static boolean fitsIn(PointF sizeLayout, @Nullable PointF sizeWidget) { return sizeWidget != null && (Math.ceil(sizeWidget.x) + 1 > sizeLayout.x) && (Math.ceil(sizeWidget.y) + 1 > sizeLayout.y); private static boolean fitsIn(SizeF sizeLayout, @Nullable SizeF sizeWidget) { return sizeWidget != null && (Math.ceil(sizeWidget.getWidth()) + 1 > sizeLayout.getWidth()) && (Math.ceil(sizeWidget.getHeight()) + 1 > sizeLayout.getHeight()); } /** * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the * size of the widget. * * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the * diagonal the most similar to the widget. If no layout fits or the size of the widget is * not specified, the one with the smallest area will be chosen. */ private RemoteViews getRemoteViewsToApply(@NonNull Context context, @Nullable PointF widgetSize) { if (!hasSizedRemoteViews()) { // If there isn't multiple remote views, fall back on the previous methods. return getRemoteViewsToApply(context); } private RemoteViews findBestFitLayout(@NonNull SizeF widgetSize) { // Find the better remote view RemoteViews bestFit = null; float bestSqDist = Float.MAX_VALUE; for (RemoteViews layout : mSizedRemoteViews) { PointF layoutSize = layout.getIdealSize(); SizeF layoutSize = layout.getIdealSize(); if (fitsIn(layoutSize, widgetSize)) { if (bestFit == null) { bestFit = layout; Loading @@ -4682,6 +4673,46 @@ public class RemoteViews implements Parcelable, Filter { return bestFit; } /** * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the * size of the widget. * * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the * diagonal the most similar to the widget. If no layout fits or the size of the widget is * not specified, the one with the smallest area will be chosen. * * @hide */ public RemoteViews getRemoteViewsToApply(@NonNull Context context, @Nullable SizeF widgetSize) { if (!hasSizedRemoteViews()) { // If there isn't multiple remote views, fall back on the previous methods. return getRemoteViewsToApply(context); } return findBestFitLayout(widgetSize); } /** * Checks whether the change of size will lead to using a different {@link RemoteViews}. * * @hide */ @Nullable public RemoteViews getRemoteViewsToApplyIfDifferent(@Nullable SizeF oldSize, @NonNull SizeF newSize) { if (!hasSizedRemoteViews()) { return null; } RemoteViews oldBestFit = oldSize == null ? findSmallestRemoteView() : findBestFitLayout( oldSize); RemoteViews newBestFit = findBestFitLayout(newSize); if (oldBestFit != newBestFit) { return newBestFit; } return null; } /** * Inflates the view hierarchy represented by this object and applies Loading @@ -4705,7 +4736,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View apply(@NonNull Context context, @NonNull ViewGroup parent, @Nullable InteractionHandler handler, @Nullable PointF size) { @Nullable InteractionHandler handler, @Nullable SizeF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent); Loading @@ -4722,7 +4753,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent, @Nullable InteractionHandler handler, @StyleRes int applyThemeResId, @Nullable PointF size) { @Nullable SizeF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent, applyThemeResId, null); Loading @@ -4732,7 +4763,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View apply(Context context, ViewGroup parent, InteractionHandler handler, @NonNull PointF size, @Nullable ColorResources colorResources) { @NonNull SizeF size, @Nullable ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent, 0, colorResources); Loading Loading @@ -4828,21 +4859,21 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size) { SizeF size) { return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */) .startTaskOnExecutor(executor); } /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { return getAsyncApplyTask(context, parent, listener, handler, size, colorResources) .startTaskOnExecutor(executor); } private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener, handler, colorResources, null /* result */); Loading Loading @@ -4968,7 +4999,7 @@ public class RemoteViews implements Parcelable, Filter { } /** @hide */ public void reapply(Context context, View v, InteractionHandler handler, PointF size, public void reapply(Context context, View v, InteractionHandler handler, SizeF size, ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); Loading Loading @@ -5012,7 +5043,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public CancellationSignal reapplyAsync(Context context, View v, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); Loading