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

Commit 7ccbcf17 authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Fill out RemoteViews methods for editing LayoutParams."

parents dfb95593 a2114a56
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -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,
+143 −1
Original line number Diff line number Diff line
@@ -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 
+205 −55

File changed.

Preview size limit exceeded, changes collapsed.

+155 −0
Original line number Diff line number Diff line
/*
 * 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)
    }
}
 No newline at end of file