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

Commit f009ecdc authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/29734187']...

Merge cherrypicks of ['googleplex-android-review.googlesource.com/29734187'] into security-aosp-24Q3-release.

Change-Id: I0b5bbf2b8a97880b98ab935235b6737ffaef7cb6
parents a337d72a a44beb0c
Loading
Loading
Loading
Loading
+58 −6
Original line number Diff line number Diff line
@@ -139,7 +139,11 @@ public final class NotificationChannel implements Parcelable {
    /**
     * @hide
     */
    public static final int MAX_VIBRATION_LENGTH = 1000;
    public static final int MAX_VIBRATION_LENGTH = 500;
    /**
     * @hide
     */
    public static final int MAX_SERIALIZED_VIBRATION_LENGTH = 32_768;

    private static final String TAG_CHANNEL = "channel";
    private static final String ATT_NAME = "name";
@@ -339,6 +343,9 @@ public final class NotificationChannel implements Parcelable {
        if (Flags.notificationChannelVibrationEffectApi()) {
            mVibrationEffect =
                    in.readInt() != 0 ? VibrationEffect.CREATOR.createFromParcel(in) : null;
            if (mVibrationEffect != null) {
                mVibrationEffect = getTrimmedVibrationEffect(mVibrationEffect);
            }
        }
        mUserLockedFields = in.readInt();
        mUserVisibleTaskShown = in.readByte() != 0;
@@ -553,6 +560,23 @@ public final class NotificationChannel implements Parcelable {
        return input;
    }

    // Returns trimmed vibration effect or null if not trimmable.
    private VibrationEffect getTrimmedVibrationEffect(VibrationEffect effect) {
        if (effect == null) {
            return null;
        }
        // trim if possible; check serialized length; reject if it is still too long
        VibrationEffect result = effect;
        VibrationEffect trimmed = effect.cropToLengthOrNull(MAX_VIBRATION_LENGTH);
        if (trimmed != null) {
            result = trimmed;
        }
        if (vibrationToString(result).length() > MAX_SERIALIZED_VIBRATION_LENGTH) {
            return null;
        }
        return result;
    }

    /**
     * @hide
     */
@@ -656,6 +680,9 @@ public final class NotificationChannel implements Parcelable {
    public void setVibrationPattern(long[] vibrationPattern) {
        this.mVibrationEnabled = vibrationPattern != null && vibrationPattern.length > 0;
        this.mVibrationPattern = vibrationPattern;
        if (vibrationPattern != null && vibrationPattern.length > MAX_VIBRATION_LENGTH) {
            this.mVibrationPattern = Arrays.copyOf(vibrationPattern, MAX_VIBRATION_LENGTH);
        }
        if (Flags.notificationChannelVibrationEffectApi()) {
            try {
                this.mVibrationEffect =
@@ -702,9 +729,29 @@ public final class NotificationChannel implements Parcelable {
    public void setVibrationEffect(@Nullable VibrationEffect effect) {
        this.mVibrationEnabled = effect != null;
        this.mVibrationEffect = effect;
        if (effect != null) {
            long[] pattern = effect.computeCreateWaveformOffOnTimingsOrNull();
            if (pattern != null) {
                // If this effect has an equivalent pattern, AND the pattern needs to be truncated
                // due to being too long, we delegate to setVibrationPattern to re-generate the
                // effect as well. Otherwise, we use the effect (already set above) and converted
                // pattern directly.
                if (pattern.length > MAX_VIBRATION_LENGTH) {
                    setVibrationPattern(pattern);
                } else {
                    this.mVibrationPattern = pattern;
                }
            } else {
                // If not convertible to a pattern directly, try trimming the vibration effect if
                // possible and storing that version instead.
                this.mVibrationEffect = getTrimmedVibrationEffect(mVibrationEffect);
                this.mVibrationPattern = null;
            }
        } else {
            this.mVibrationPattern =
                effect == null
                ? null : effect.computeCreateWaveformOffOnTimingsOrNull();
                    mVibrationEffect == null
                            ? null : mVibrationEffect.computeCreateWaveformOffOnTimingsOrNull();
        }
    }

    /**
@@ -1138,7 +1185,8 @@ public final class NotificationChannel implements Parcelable {
            if (vibrationEffect != null) {
                // Restore the effect only if it is not null. This allows to avoid undoing a
                // `setVibrationPattern` call above, if that was done with a non-null pattern
                // (e.g. back up from a version that did not support `setVibrationEffect`).
                // (e.g. back up from a version that did not support `setVibrationEffect`), or
                // if there is an equivalent vibration pattern available.
                setVibrationEffect(vibrationEffect);
            }
        }
@@ -1331,8 +1379,12 @@ public final class NotificationChannel implements Parcelable {
            out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
        }
        if (getVibrationEffect() != null) {
            if (getVibrationPattern() == null) {
                // Only serialize the vibration effect if we do not already have an equivalent
                // vibration pattern.
                out.attribute(null, ATT_VIBRATION_EFFECT, vibrationToString(getVibrationEffect()));
            }
        }
        if (getUserLockedFields() != 0) {
            out.attributeInt(null, ATT_USER_LOCKED, getUserLockedFields());
        }
+35 −0
Original line number Diff line number Diff line
@@ -504,6 +504,17 @@ public abstract class VibrationEffect implements Parcelable {
    /** @hide */
    public abstract void validate();


    /**
     * If supported, truncate the length of this vibration effect to the provided length and return
     * the result. Will always return null for repeating effects.
     *
     * @return The desired effect, or {@code null} if truncation is not applicable.
     * @hide
     */
    @Nullable
    public abstract VibrationEffect cropToLengthOrNull(int length);

    /**
     * Gets the estimated duration of the vibration in milliseconds.
     *
@@ -805,6 +816,30 @@ public abstract class VibrationEffect implements Parcelable {
            }
        }

        /** @hide */
        @Override
        @Nullable
        public VibrationEffect cropToLengthOrNull(int length) {
            // drop repeating effects
            if (mRepeatIndex >= 0) {
                return null;
            }

            int segmentCount = mSegments.size();
            if (segmentCount <= length) {
                return this;
            }

            ArrayList truncated = new ArrayList(mSegments.subList(0, length));
            Composed updated = new Composed(truncated, mRepeatIndex);
            try {
                updated.validate();
            } catch (IllegalArgumentException e) {
                return null;
            }
            return updated;
        }

        @Override
        public long getDuration() {
            if (mRepeatIndex >= 0) {
+26 −0
Original line number Diff line number Diff line
@@ -234,6 +234,32 @@ public class NotificationChannelTest {
                fromParcel.getSound().toString().length());
    }

    @Test
    @EnableFlags(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API)
    public void testLongVibrationFields_canWriteToXml() throws Exception {
        NotificationChannel channel = new NotificationChannel("id", "name", 3);
        // populate pattern with contents
        long[] pattern = new long[65550 / 2];
        for (int i = 0; i < pattern.length; i++) {
            pattern[i] = 100;
        }
        channel.setVibrationPattern(pattern);  // with flag on, also sets effect

        // Send it through parceling & unparceling to simulate being passed through a binder call
        NotificationChannel fromParcel = writeToAndReadFromParcel(channel);
        assertThat(fromParcel.getVibrationPattern().length).isEqualTo(
                NotificationChannel.MAX_VIBRATION_LENGTH);

        // Confirm that this also survives writing to & restoring from XML
        NotificationChannel result = backUpAndRestore(fromParcel);
        assertThat(result.getVibrationPattern().length).isEqualTo(
                NotificationChannel.MAX_VIBRATION_LENGTH);
        assertThat(result.getVibrationEffect()).isNotNull();
        assertThat(result.getVibrationEffect()
                .computeCreateWaveformOffOnTimingsOrNull())
                .isEqualTo(result.getVibrationPattern());
    }

    @Test
    public void testRestoreSoundUri_customLookup() throws Exception {
        Uri uriToBeRestoredUncanonicalized = Uri.parse("content://media/1");
+72 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.os.VibrationEffect.DEFAULT_AMPLITUDE;
import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
import static android.os.VibrationEffect.VibrationParameter.targetFrequency;

import static com.google.common.truth.Truth.assertThat;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -419,6 +421,76 @@ public class VibrationEffectTest {
        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
    }

    @Test
    public void cropToLength_waveform_underLength() {
        VibrationEffect effect = VibrationEffect.createWaveform(
                /* timings= */ new long[]{0, 1, 2},
                /* repeatIndex= */ -1);
        VibrationEffect result = effect.cropToLengthOrNull(5);

        assertThat(result).isEqualTo(effect); // unchanged
    }

    @Test
    public void cropToLength_waveform_overLength() {
        VibrationEffect effect = VibrationEffect.createWaveform(
                /* timings= */ new long[]{0, 1, 2, 3, 4, 5, 6},
                /* repeatIndex= */ -1);
        VibrationEffect result = effect.cropToLengthOrNull(4);

        assertThat(result).isEqualTo(VibrationEffect.createWaveform(
                new long[]{0, 1, 2, 3},
                -1));
    }

    @Test
    public void cropToLength_waveform_repeating() {
        // repeating waveforms cannot be truncated
        VibrationEffect effect = VibrationEffect.createWaveform(
                /* timings= */ new long[]{0, 1, 2, 3, 4, 5, 6},
                /* repeatIndex= */ 2);
        VibrationEffect result = effect.cropToLengthOrNull(3);

        assertThat(result).isNull();
    }

    @Test
    public void cropToLength_waveform_withAmplitudes() {
        VibrationEffect effect = VibrationEffect.createWaveform(
                /* timings= */ new long[]{0, 1, 2, 3, 4, 5, 6},
                /* amplitudes= */ new int[]{10, 20, 40, 10, 20, 40, 10},
                /* repeatIndex= */ -1);
        VibrationEffect result = effect.cropToLengthOrNull(3);

        assertThat(result).isEqualTo(VibrationEffect.createWaveform(
                new long[]{0, 1, 2},
                new int[]{10, 20, 40},
                -1));
    }

    @Test
    public void cropToLength_composed() {
        VibrationEffect effect = VibrationEffect.startComposition()
                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
                .compose();
        VibrationEffect result = effect.cropToLengthOrNull(1);

        assertThat(result).isNotNull();
        assertThat(result).isEqualTo(VibrationEffect.startComposition()
                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                        .compose());
    }

    @Test
    public void cropToLength_composed_repeating() {
        VibrationEffect effect = VibrationEffect.startComposition()
                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                .repeatEffectIndefinitely(TEST_ONE_SHOT)
                .compose();
        assertThat(effect.cropToLengthOrNull(1)).isNull();
    }

    @Test
    public void getRingtones_noPrebakedRingtones() {
        Resources r = mockRingtoneResources(new String[0]);