Merge "Fill out RemoteViews methods for editing LayoutParams."
This commit is contained in:
@@ -83,6 +83,7 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.Gravity;
|
||||
@@ -4920,7 +4921,8 @@ public class Notification implements Parcelable
|
||||
setTextViewColorPrimary(contentView, R.id.title, p);
|
||||
contentView.setViewLayoutWidth(R.id.title, showProgress
|
||||
? ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
: ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
: ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
TypedValue.COMPLEX_UNIT_PX);
|
||||
}
|
||||
if (p.text != null && p.text.length() != 0) {
|
||||
int textId = showProgress ? com.android.internal.R.id.text_line_1
|
||||
@@ -5365,8 +5367,9 @@ public class Notification implements Parcelable
|
||||
final boolean snoozeEnabled = mContext.getContentResolver() != null
|
||||
&& (Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
|
||||
big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
|
||||
snoozeEnabled ? 0 : R.dimen.notification_content_margin);
|
||||
int bottomMarginDimen = snoozeEnabled ? 0 : R.dimen.notification_content_margin;
|
||||
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
|
||||
RemoteViews.MARGIN_BOTTOM, bottomMarginDimen);
|
||||
}
|
||||
|
||||
private static List<Notification.Action> filterOutContextualActions(
|
||||
@@ -5398,7 +5401,8 @@ public class Notification implements Parcelable
|
||||
if (N > 0) {
|
||||
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
|
||||
big.setViewVisibility(R.id.actions, View.VISIBLE);
|
||||
big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target, 0);
|
||||
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
|
||||
RemoteViews.MARGIN_BOTTOM, 0);
|
||||
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
|
||||
for (int i=0; i<N; i++) {
|
||||
Action action = nonContextualActions.get(i);
|
||||
@@ -7797,8 +7801,8 @@ public class Notification implements Parcelable
|
||||
// also update the end margin if there is an image
|
||||
// NOTE: This template doesn't support moving this icon to the left, so we don't
|
||||
// need to fully apply the MarginSet
|
||||
contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
|
||||
bindResult.mHeadingExtraMarginSet.getValue());
|
||||
contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END,
|
||||
bindResult.mHeadingExtraMarginSet.getValue(), TypedValue.COMPLEX_UNIT_PX);
|
||||
}
|
||||
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
|
||||
mBuilder.isColorized(p)
|
||||
@@ -8622,7 +8626,8 @@ public class Notification implements Parcelable
|
||||
if (mBuilder.mN.hasLargeIcon()) {
|
||||
endMargin = R.dimen.notification_media_image_margin_end;
|
||||
}
|
||||
view.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
|
||||
view.setViewLayoutMarginDimen(R.id.notification_main_column,
|
||||
RemoteViews.MARGIN_END, endMargin);
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -8659,8 +8664,8 @@ public class Notification implements Parcelable
|
||||
|
||||
private void handleImage(RemoteViews contentView) {
|
||||
if (mBuilder.mN.hasLargeIcon()) {
|
||||
contentView.setViewLayoutMarginEndDimen(R.id.line1, 0);
|
||||
contentView.setViewLayoutMarginEndDimen(R.id.text, 0);
|
||||
contentView.setViewLayoutMarginDimen(R.id.line1, RemoteViews.MARGIN_END, 0);
|
||||
contentView.setViewLayoutMarginDimen(R.id.text, RemoteViews.MARGIN_END, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11089,7 +11094,8 @@ public class Notification implements Parcelable
|
||||
if (viewId == R.id.notification_header) {
|
||||
views.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", marginEnd);
|
||||
} else {
|
||||
views.setViewLayoutMarginEnd(viewId, marginEnd);
|
||||
views.setViewLayoutMargin(viewId, RemoteViews.MARGIN_END,
|
||||
marginEnd, TypedValue.COMPLEX_UNIT_PX);
|
||||
}
|
||||
if (mRightIconVisible) {
|
||||
views.setIntTag(viewId, R.id.tag_margin_end_when_icon_visible,
|
||||
|
||||
@@ -17,8 +17,14 @@
|
||||
package android.util;
|
||||
|
||||
import android.annotation.AnyRes;
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.content.pm.ActivityInfo.Config;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Container for a dynamically typed data value. Primarily used with
|
||||
* {@link android.content.res.Resources} for holding resource values.
|
||||
@@ -95,6 +101,18 @@ public class TypedValue {
|
||||
* defined below. */
|
||||
public static final int COMPLEX_UNIT_MASK = 0xf;
|
||||
|
||||
/** @hide **/
|
||||
@IntDef(prefix = "COMPLEX_UNIT_", value = {
|
||||
COMPLEX_UNIT_PX,
|
||||
COMPLEX_UNIT_DIP,
|
||||
COMPLEX_UNIT_SP,
|
||||
COMPLEX_UNIT_PT,
|
||||
COMPLEX_UNIT_IN,
|
||||
COMPLEX_UNIT_MM,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ComplexDimensionUnit {}
|
||||
|
||||
/** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
|
||||
public static final int COMPLEX_UNIT_PX = 0;
|
||||
/** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent
|
||||
@@ -381,7 +399,7 @@ public class TypedValue {
|
||||
* @return The complex floating point value multiplied by the appropriate
|
||||
* metrics depending on its unit.
|
||||
*/
|
||||
public static float applyDimension(int unit, float value,
|
||||
public static float applyDimension(@ComplexDimensionUnit int unit, float value,
|
||||
DisplayMetrics metrics)
|
||||
{
|
||||
switch (unit) {
|
||||
@@ -416,6 +434,130 @@ public class TypedValue {
|
||||
return complexToDimension(data, metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a complex data integer. This validates the radix and the magnitude of the
|
||||
* mantissa, and sets the {@link TypedValue#COMPLEX_MANTISSA_MASK} and
|
||||
* {@link TypedValue#COMPLEX_RADIX_MASK} components as provided. The units are not set.
|
||||
**
|
||||
* @param mantissa an integer representing the mantissa.
|
||||
* @param radix a radix option, e.g. {@link TypedValue#COMPLEX_RADIX_23p0}.
|
||||
* @return A complex data integer representing the value.
|
||||
* @hide
|
||||
*/
|
||||
private static int createComplex(@IntRange(from = -0x800000, to = 0x7FFFFF) int mantissa,
|
||||
int radix) {
|
||||
if (mantissa < -0x800000 || mantissa >= 0x800000) {
|
||||
throw new IllegalArgumentException("Magnitude of mantissa is too large: " + mantissa);
|
||||
}
|
||||
if (radix < TypedValue.COMPLEX_RADIX_23p0 || radix > TypedValue.COMPLEX_RADIX_0p23) {
|
||||
throw new IllegalArgumentException("Invalid radix: " + radix);
|
||||
}
|
||||
return ((mantissa & TypedValue.COMPLEX_MANTISSA_MASK) << TypedValue.COMPLEX_MANTISSA_SHIFT)
|
||||
| (radix << TypedValue.COMPLEX_RADIX_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a base value to a complex data integer. This sets the {@link
|
||||
* TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the
|
||||
* data to create a floating point representation of the given value. The units are not set.
|
||||
*
|
||||
* <p>This is the inverse of {@link TypedValue#complexToFloat(int)}.
|
||||
*
|
||||
* @param value An integer value.
|
||||
* @return A complex data integer representing the value.
|
||||
* @hide
|
||||
*/
|
||||
public static int intToComplex(int value) {
|
||||
if (value < -0x800000 || value >= 0x800000) {
|
||||
throw new IllegalArgumentException("Magnitude of the value is too large: " + value);
|
||||
}
|
||||
return createComplex(value, TypedValue.COMPLEX_RADIX_23p0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a base value to a complex data integer. This sets the {@link
|
||||
* TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the
|
||||
* data to create a floating point representation of the given value. The units are not set.
|
||||
*
|
||||
* <p>This is the inverse of {@link TypedValue#complexToFloat(int)}.
|
||||
*
|
||||
* @param value A floating point value.
|
||||
* @return A complex data integer representing the value.
|
||||
* @hide
|
||||
*/
|
||||
public static int floatToComplex(@FloatRange(from = -0x800000, to = 0x7FFFFF) float value) {
|
||||
// validate that the magnitude fits in this representation
|
||||
if (value < (float) -0x800000 - .5f || value >= (float) 0x800000 - .5f) {
|
||||
throw new IllegalArgumentException("Magnitude of the value is too large: " + value);
|
||||
}
|
||||
try {
|
||||
// If there's no fraction, use integer representation, as that's clearer
|
||||
if (value == (float) (int) value) {
|
||||
return createComplex((int) value, TypedValue.COMPLEX_RADIX_23p0);
|
||||
}
|
||||
float absValue = Math.abs(value);
|
||||
// If the magnitude is 0, we don't need any magnitude digits
|
||||
if (absValue < 1f) {
|
||||
return createComplex(Math.round(value * (1 << 23)), TypedValue.COMPLEX_RADIX_0p23);
|
||||
}
|
||||
// If the magnitude is less than 2^8, use 8 magnitude digits
|
||||
if (absValue < (float) (1 << 8)) {
|
||||
return createComplex(Math.round(value * (1 << 15)), TypedValue.COMPLEX_RADIX_8p15);
|
||||
}
|
||||
// If the magnitude is less than 2^16, use 16 magnitude digits
|
||||
if (absValue < (float) (1 << 16)) {
|
||||
return createComplex(Math.round(value * (1 << 7)), TypedValue.COMPLEX_RADIX_16p7);
|
||||
}
|
||||
// The magnitude requires all 23 digits
|
||||
return createComplex(Math.round(value), TypedValue.COMPLEX_RADIX_23p0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Wrap exception so as to include the value argument in the message.
|
||||
throw new IllegalArgumentException("Unable to convert value to complex: " + value, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates a complex data integer that stores a dimension value and units.
|
||||
*
|
||||
* <p>The resulting value can be passed to e.g.
|
||||
* {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel
|
||||
* value for the dimension.
|
||||
*
|
||||
* @param value the value of the dimension
|
||||
* @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
|
||||
* @return A complex data integer representing the value and units of the dimension.
|
||||
* @hide
|
||||
*/
|
||||
public static int createComplexDimension(
|
||||
@IntRange(from = -0x800000, to = 0x7FFFFF) int value,
|
||||
@ComplexDimensionUnit int units) {
|
||||
if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) {
|
||||
throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units);
|
||||
}
|
||||
return intToComplex(value) | units;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates a complex data integer that stores a dimension value and units.
|
||||
*
|
||||
* <p>The resulting value can be passed to e.g.
|
||||
* {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel
|
||||
* value for the dimension.
|
||||
*
|
||||
* @param value the value of the dimension
|
||||
* @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
|
||||
* @return A complex data integer representing the value and units of the dimension.
|
||||
* @hide
|
||||
*/
|
||||
public static int createComplexDimension(
|
||||
@FloatRange(from = -0x800000, to = 0x7FFFFF) float value,
|
||||
@ComplexDimensionUnit int units) {
|
||||
if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) {
|
||||
throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units);
|
||||
}
|
||||
return floatToComplex(value) | units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a complex data value holding a fraction to its final floating
|
||||
* point value. The given <var>data</var> must be structured as a
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.widget;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.DimenRes;
|
||||
import android.annotation.IdRes;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.LayoutRes;
|
||||
import android.annotation.NonNull;
|
||||
@@ -63,12 +64,15 @@ import android.util.ArrayMap;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.TypedValue;
|
||||
import android.util.TypedValue.ComplexDimensionUnit;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.LayoutInflater.Filter;
|
||||
import android.view.RemotableViewMethod;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.view.ViewStub;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
@@ -172,6 +176,48 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
|
||||
private static final int SET_INT_TAG_TAG = 22;
|
||||
|
||||
/** @hide **/
|
||||
@IntDef(prefix = "MARGIN_", value = {
|
||||
MARGIN_LEFT,
|
||||
MARGIN_TOP,
|
||||
MARGIN_RIGHT,
|
||||
MARGIN_BOTTOM,
|
||||
MARGIN_START,
|
||||
MARGIN_END
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface MarginType {}
|
||||
/**
|
||||
* The value will apply to the marginLeft.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_LEFT = 0;
|
||||
/**
|
||||
* The value will apply to the marginTop.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_TOP = 1;
|
||||
/**
|
||||
* The value will apply to the marginRight.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_RIGHT = 2;
|
||||
/**
|
||||
* The value will apply to the marginBottom.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_BOTTOM = 3;
|
||||
/**
|
||||
* The value will apply to the marginStart.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_START = 4;
|
||||
/**
|
||||
* The value will apply to the marginEnd.
|
||||
* @hide
|
||||
*/
|
||||
public static final int MARGIN_END = 5;
|
||||
|
||||
/** @hide **/
|
||||
@IntDef(flag = true, value = {
|
||||
FLAG_REAPPLY_DISALLOWED,
|
||||
@@ -1730,8 +1776,16 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
|
||||
final ViewGroup targetVg = (ViewGroup) target.mRoot;
|
||||
|
||||
// Clear all children when nested views omitted
|
||||
target.mChildren = null;
|
||||
if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
|
||||
// Clear all children when there's no excepted view
|
||||
target.mChildren = null;
|
||||
} else {
|
||||
// Remove just the children which don't match the excepted view
|
||||
target.mChildren.removeIf(childTree -> childTree.mRoot.getId() != mViewIdToKeep);
|
||||
if (target.mChildren.isEmpty()) {
|
||||
target.mChildren = null;
|
||||
}
|
||||
}
|
||||
return new RuntimeAction() {
|
||||
@Override
|
||||
public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
|
||||
@@ -1922,13 +1976,13 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
* Helper action to set text size on a TextView in any supported units.
|
||||
*/
|
||||
private class TextViewSizeAction extends Action {
|
||||
public TextViewSizeAction(int viewId, int units, float size) {
|
||||
TextViewSizeAction(@IdRes int viewId, @ComplexDimensionUnit int units, float size) {
|
||||
this.viewId = viewId;
|
||||
this.units = units;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public TextViewSizeAction(Parcel parcel) {
|
||||
TextViewSizeAction(Parcel parcel) {
|
||||
viewId = parcel.readInt();
|
||||
units = parcel.readInt();
|
||||
size = parcel.readFloat();
|
||||
@@ -2004,36 +2058,56 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
*/
|
||||
private static class LayoutParamAction extends Action {
|
||||
|
||||
/** Set marginEnd */
|
||||
public static final int LAYOUT_MARGIN_END_DIMEN = 1;
|
||||
/** Set width */
|
||||
public static final int LAYOUT_WIDTH = 2;
|
||||
public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3;
|
||||
public static final int LAYOUT_MARGIN_END = 4;
|
||||
static final int LAYOUT_MARGIN_LEFT = MARGIN_LEFT;
|
||||
static final int LAYOUT_MARGIN_TOP = MARGIN_TOP;
|
||||
static final int LAYOUT_MARGIN_RIGHT = MARGIN_RIGHT;
|
||||
static final int LAYOUT_MARGIN_BOTTOM = MARGIN_BOTTOM;
|
||||
static final int LAYOUT_MARGIN_START = MARGIN_START;
|
||||
static final int LAYOUT_MARGIN_END = MARGIN_END;
|
||||
static final int LAYOUT_WIDTH = 8;
|
||||
static final int LAYOUT_HEIGHT = 9;
|
||||
|
||||
final int mProperty;
|
||||
final boolean mIsDimen;
|
||||
final int mValue;
|
||||
|
||||
/**
|
||||
* @param viewId ID of the view alter
|
||||
* @param property which layout parameter to alter
|
||||
* @param value new value of the layout parameter
|
||||
* @param units the units of the given value
|
||||
*/
|
||||
public LayoutParamAction(int viewId, int property, int value) {
|
||||
LayoutParamAction(@IdRes int viewId, int property, float value,
|
||||
@ComplexDimensionUnit int units) {
|
||||
this.viewId = viewId;
|
||||
this.mProperty = property;
|
||||
this.mValue = value;
|
||||
this.mIsDimen = false;
|
||||
this.mValue = TypedValue.createComplexDimension(value, units);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param viewId ID of the view alter
|
||||
* @param property which layout parameter to alter
|
||||
* @param dimen new dimension with the value of the layout parameter
|
||||
*/
|
||||
LayoutParamAction(@IdRes int viewId, int property, @DimenRes int dimen) {
|
||||
this.viewId = viewId;
|
||||
this.mProperty = property;
|
||||
this.mIsDimen = true;
|
||||
this.mValue = dimen;
|
||||
}
|
||||
|
||||
public LayoutParamAction(Parcel parcel) {
|
||||
viewId = parcel.readInt();
|
||||
mProperty = parcel.readInt();
|
||||
mIsDimen = parcel.readBoolean();
|
||||
mValue = parcel.readInt();
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(viewId);
|
||||
dest.writeInt(mProperty);
|
||||
dest.writeBoolean(mIsDimen);
|
||||
dest.writeInt(mValue);
|
||||
}
|
||||
|
||||
@@ -2047,26 +2121,49 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
if (layoutParams == null) {
|
||||
return;
|
||||
}
|
||||
int value = mValue;
|
||||
switch (mProperty) {
|
||||
case LAYOUT_MARGIN_END_DIMEN:
|
||||
value = resolveDimenPixelOffset(target, mValue);
|
||||
// fall-through
|
||||
case LAYOUT_MARGIN_END:
|
||||
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||
((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
|
||||
case LAYOUT_MARGIN_LEFT:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).leftMargin = getPixelOffset(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_MARGIN_BOTTOM_DIMEN:
|
||||
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||
int resolved = resolveDimenPixelOffset(target, mValue);
|
||||
((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = resolved;
|
||||
case LAYOUT_MARGIN_TOP:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).topMargin = getPixelOffset(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_MARGIN_RIGHT:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).rightMargin = getPixelOffset(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_MARGIN_BOTTOM:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).bottomMargin = getPixelOffset(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_MARGIN_START:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).setMarginStart(getPixelOffset(target));
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_MARGIN_END:
|
||||
if (layoutParams instanceof MarginLayoutParams) {
|
||||
((MarginLayoutParams) layoutParams).setMarginEnd(getPixelOffset(target));
|
||||
target.setLayoutParams(layoutParams);
|
||||
}
|
||||
break;
|
||||
case LAYOUT_WIDTH:
|
||||
layoutParams.width = mValue;
|
||||
layoutParams.width = getPixelSize(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
break;
|
||||
case LAYOUT_HEIGHT:
|
||||
layoutParams.height = getPixelSize(target);
|
||||
target.setLayoutParams(layoutParams);
|
||||
break;
|
||||
default:
|
||||
@@ -2074,11 +2171,26 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveDimenPixelOffset(View target, int value) {
|
||||
if (value == 0) {
|
||||
return 0;
|
||||
private int getPixelOffset(View target) {
|
||||
if (mIsDimen) {
|
||||
if (mValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
return target.getResources().getDimensionPixelOffset(mValue);
|
||||
}
|
||||
return target.getContext().getResources().getDimensionPixelOffset(value);
|
||||
return TypedValue.complexToDimensionPixelOffset(mValue,
|
||||
target.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
private int getPixelSize(View target) {
|
||||
if (mIsDimen) {
|
||||
if (mValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
return target.getResources().getDimensionPixelSize(mValue);
|
||||
}
|
||||
return TypedValue.complexToDimensionPixelSize(mValue,
|
||||
target.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2512,6 +2624,7 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
* @param nestedView {@link RemoteViews} that describes the child.
|
||||
*/
|
||||
public void addView(int viewId, RemoteViews nestedView) {
|
||||
// Clear all children when nested views omitted
|
||||
addAction(nestedView == null
|
||||
? new ViewGroupActionRemove(viewId)
|
||||
: new ViewGroupActionAdd(viewId, nestedView));
|
||||
@@ -3044,57 +3157,94 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}.
|
||||
* Equivalent to calling {@link MarginLayoutParams#setMarginEnd}.
|
||||
* Only works if the {@link View#getLayoutParams()} supports margins.
|
||||
* Hidden for now since we don't want to support this for all different layout margins yet.
|
||||
*
|
||||
* @param viewId The id of the view to change
|
||||
* @param endMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
|
||||
* @param type The margin being set e.g. {@link #MARGIN_END}
|
||||
* @param dimen a dimension resource to apply to the margin, or 0 to clear the margin.
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutMarginEndDimen(int viewId, @DimenRes int endMarginDimen) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END_DIMEN,
|
||||
endMarginDimen));
|
||||
public void setViewLayoutMarginDimen(@IdRes int viewId, @MarginType int type,
|
||||
@DimenRes int dimen) {
|
||||
addAction(new LayoutParamAction(viewId, type, dimen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}.
|
||||
* Equivalent to calling {@link MarginLayoutParams#setMarginEnd}.
|
||||
* Only works if the {@link View#getLayoutParams()} supports margins.
|
||||
* Hidden for now since we don't want to support this for all different layout margins yet.
|
||||
*
|
||||
* <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0.
|
||||
* Setting margins in pixels will behave poorly when the RemoteViews object is used on a
|
||||
* display with a different density.
|
||||
*
|
||||
* @param viewId The id of the view to change
|
||||
* @param endMargin a value in pixels for the end margin.
|
||||
* @param type The margin being set e.g. {@link #MARGIN_END}
|
||||
* @param value a value for the margin the given units.
|
||||
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutMarginEnd(int viewId, @DimenRes int endMargin) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END,
|
||||
endMargin));
|
||||
public void setViewLayoutMargin(@IdRes int viewId, @MarginType int type, float value,
|
||||
@ComplexDimensionUnit int units) {
|
||||
addAction(new LayoutParamAction(viewId, type, value, units));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}.
|
||||
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width} except that you may
|
||||
* provide the value in any dimension units.
|
||||
*
|
||||
* @param bottomMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
|
||||
* <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0,
|
||||
* {@link ViewGroup.LayoutParams#WRAP_CONTENT}, or {@link ViewGroup.LayoutParams#MATCH_PARENT}.
|
||||
* Setting actual sizes in pixels will behave poorly when the RemoteViews object is used on a
|
||||
* display with a different density.
|
||||
*
|
||||
* @param width Width of the view in the given units
|
||||
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutMarginBottomDimen(int viewId, @DimenRes int bottomMarginDimen) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM_DIMEN,
|
||||
bottomMarginDimen));
|
||||
public void setViewLayoutWidth(@IdRes int viewId, float width,
|
||||
@ComplexDimensionUnit int units) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, width, units));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
|
||||
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width} with
|
||||
* the result of {@link Resources#getDimensionPixelSize(int)}.
|
||||
*
|
||||
* @param layoutWidth one of 0, MATCH_PARENT or WRAP_CONTENT. Other sizes are not allowed
|
||||
* because they behave poorly when the density changes.
|
||||
* @param widthDimen the dimension resource for the view's width
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutWidth(int viewId, int layoutWidth) {
|
||||
if (layoutWidth != 0 && layoutWidth != ViewGroup.LayoutParams.MATCH_PARENT
|
||||
&& layoutWidth != ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
throw new IllegalArgumentException("Only supports 0, WRAP_CONTENT and MATCH_PARENT");
|
||||
}
|
||||
mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
|
||||
public void setViewLayoutWidthDimen(@IdRes int viewId, @DimenRes int widthDimen) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, widthDimen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#height} except that you may
|
||||
* provide the value in any dimension units.
|
||||
*
|
||||
* <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0,
|
||||
* {@link ViewGroup.LayoutParams#WRAP_CONTENT}, or {@link ViewGroup.LayoutParams#MATCH_PARENT}.
|
||||
* Setting actual sizes in pixels will behave poorly when the RemoteViews object is used on a
|
||||
* display with a different density.
|
||||
*
|
||||
* @param height height of the view in the given units
|
||||
* @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutHeight(@IdRes int viewId, float height,
|
||||
@ComplexDimensionUnit int units) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_HEIGHT, height, units));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#height} with
|
||||
* the result of {@link Resources#getDimensionPixelSize(int)}.
|
||||
*
|
||||
* @param heightDimen a dimen resource to read the height from.
|
||||
* @hide
|
||||
*/
|
||||
public void setViewLayoutHeightDimen(@IdRes int viewId, @DimenRes int heightDimen) {
|
||||
addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_HEIGHT, heightDimen));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
155
core/tests/coretests/src/android/util/TypedValueTest.kt
Normal file
155
core/tests/coretests/src/android/util/TypedValueTest.kt
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 android.util
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.mock
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TypedValueTest {
|
||||
@LargeTest
|
||||
@Test
|
||||
fun testFloatToComplex() {
|
||||
fun assertRoundTripEquals(value: Float, expectedRadix: Int? = null) {
|
||||
val complex = TypedValue.floatToComplex(value)
|
||||
// Ensure values are accurate within .5% of the original value and within .5
|
||||
val delta = min(abs(value) / 512f, .5f)
|
||||
assertEquals(value, TypedValue.complexToFloat(complex), delta)
|
||||
// If expectedRadix is provided, validate it
|
||||
if (expectedRadix != null) {
|
||||
val actualRadix = ((complex shr TypedValue.COMPLEX_RADIX_SHIFT)
|
||||
and TypedValue.COMPLEX_RADIX_MASK)
|
||||
assertEquals("Incorrect radix for $value:", expectedRadix, actualRadix)
|
||||
}
|
||||
}
|
||||
|
||||
assertRoundTripEquals(0f, TypedValue.COMPLEX_RADIX_23p0)
|
||||
|
||||
assertRoundTripEquals(0.5f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(0.05f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(0.005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(0.0005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(0.00005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
|
||||
assertRoundTripEquals(1.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(10.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(100.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(255.5f, TypedValue.COMPLEX_RADIX_8p15) // 2^8 - .5
|
||||
|
||||
assertRoundTripEquals(256.5f, TypedValue.COMPLEX_RADIX_16p7) // 2^8 + .5
|
||||
assertRoundTripEquals(1000.5f, TypedValue.COMPLEX_RADIX_16p7)
|
||||
assertRoundTripEquals(10000.5f, TypedValue.COMPLEX_RADIX_16p7)
|
||||
assertRoundTripEquals(65535.5f, TypedValue.COMPLEX_RADIX_16p7) // 2^16 - .5
|
||||
|
||||
assertRoundTripEquals(65536.5f, TypedValue.COMPLEX_RADIX_23p0) // 2^16 + .5
|
||||
assertRoundTripEquals(100000.5f, TypedValue.COMPLEX_RADIX_23p0)
|
||||
assertRoundTripEquals(1000000.5f, TypedValue.COMPLEX_RADIX_23p0)
|
||||
assertRoundTripEquals(8388607.2f, TypedValue.COMPLEX_RADIX_23p0) // 2^23 -.8
|
||||
|
||||
assertRoundTripEquals(-0.5f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(-0.05f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(-0.005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(-0.0005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
assertRoundTripEquals(-0.00005f, TypedValue.COMPLEX_RADIX_0p23)
|
||||
|
||||
assertRoundTripEquals(-1.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(-10.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(-100.5f, TypedValue.COMPLEX_RADIX_8p15)
|
||||
assertRoundTripEquals(-255.5f, TypedValue.COMPLEX_RADIX_8p15) // -2^8 + .5
|
||||
|
||||
// NOTE: -256.5f fits in COMPLEX_RADIX_8p15 but is stored with COMPLEX_RADIX_16p7 for
|
||||
// simplicity of the algorithm. However, it's better not to enforce that with a test.
|
||||
assertRoundTripEquals(-257.5f, TypedValue.COMPLEX_RADIX_16p7) // -2^8 - 1.5
|
||||
assertRoundTripEquals(-1000.5f, TypedValue.COMPLEX_RADIX_16p7)
|
||||
assertRoundTripEquals(-10000.5f, TypedValue.COMPLEX_RADIX_16p7)
|
||||
assertRoundTripEquals(-65535.5f, TypedValue.COMPLEX_RADIX_16p7) // -2^16 + .5
|
||||
|
||||
// NOTE: -65536.5f fits in COMPLEX_RADIX_16p7 but is stored with COMPLEX_RADIX_23p0 for
|
||||
// simplicity of the algorithm. However, it's better not to enforce that with a test.
|
||||
assertRoundTripEquals(-65537.5f, TypedValue.COMPLEX_RADIX_23p0) // -2^16 - 1.5
|
||||
assertRoundTripEquals(-100000.5f, TypedValue.COMPLEX_RADIX_23p0)
|
||||
assertRoundTripEquals(-1000000.5f, TypedValue.COMPLEX_RADIX_23p0)
|
||||
assertRoundTripEquals(-8388607.5f, TypedValue.COMPLEX_RADIX_23p0) // 2^23 -.5
|
||||
|
||||
// Test for every integer value in the range...
|
||||
for (i: Int in -(1 shl 23) until (1 shl 23)) {
|
||||
// ... that true integers are stored as the precise integer
|
||||
assertRoundTripEquals(i.toFloat(), TypedValue.COMPLEX_RADIX_23p0)
|
||||
// ... that values round up when just below an integer
|
||||
assertRoundTripEquals(i - .1f)
|
||||
// ... that values round down when just above an integer
|
||||
assertRoundTripEquals(i + .1f)
|
||||
}
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun testFloatToComplex_failsIfValueTooLarge() {
|
||||
TypedValue.floatToComplex(8388607.5f) // 2^23 - .5
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun testFloatToComplex_failsIfValueTooSmall() {
|
||||
TypedValue.floatToComplex(8388608.5f) // -2^23 - .5
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
fun testIntToComplex() {
|
||||
// Validates every single valid value
|
||||
for (value: Int in -(1 shl 23) until (1 shl 23)) {
|
||||
assertEquals(value.toFloat(), TypedValue.complexToFloat(TypedValue.intToComplex(value)))
|
||||
}
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun testIntToComplex_failsIfValueTooLarge() {
|
||||
TypedValue.intToComplex(0x800000)
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun testIntToComplex_failsIfValueTooSmall() {
|
||||
TypedValue.intToComplex(-0x800001)
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@Test
|
||||
fun testCreateComplexDimension_appliesUnits() {
|
||||
val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
|
||||
metrics.density = 3.25f
|
||||
|
||||
val height = 52 * metrics.density
|
||||
val widthFloat = height * 16 / 9
|
||||
val widthDimen = TypedValue.createComplexDimension(
|
||||
widthFloat / metrics.density,
|
||||
TypedValue.COMPLEX_UNIT_DIP
|
||||
)
|
||||
val widthPx = TypedValue.complexToDimensionPixelSize(widthDimen, metrics)
|
||||
assertEquals(widthFloat.roundToInt(), widthPx)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user