diff options
10 files changed, 498 insertions, 304 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5393475addf4..9e2872f8f6cc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -11471,6 +11471,19 @@ package android.os.storage { } +package android.os.vibrator.persistence { + + @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class ParsedVibration { + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator); + } + + @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class VibrationXmlParser { + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.vibrator.persistence.ParsedVibration parse(@NonNull java.io.InputStream) throws java.io.IOException; + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.InputStream) throws java.io.IOException; + } + +} + package android.permission { public final class AdminPermissionControlParams implements android.os.Parcelable { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index d8995110d167..1352465b892d 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2761,21 +2761,24 @@ package android.os.vibrator { package android.os.vibrator.persistence { - public class ParsedVibration { - method @NonNull public java.util.List<android.os.VibrationEffect> getVibrationEffects(); - method @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator); + @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class ParsedVibration { + ctor public ParsedVibration(@NonNull java.util.List<android.os.VibrationEffect>); + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator); } - public final class VibrationXmlParser { - method @Nullable public static android.os.vibrator.persistence.ParsedVibration parseDocument(@NonNull java.io.Reader) throws java.io.IOException; - method @Nullable public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.Reader) throws java.io.IOException; + @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class VibrationXmlParser { + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.vibrator.persistence.ParsedVibration parse(@NonNull java.io.InputStream) throws java.io.IOException; + method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.InputStream) throws java.io.IOException; + } + + public static final class VibrationXmlParser.ParseFailedException extends java.io.IOException { } public final class VibrationXmlSerializer { - method public static void serialize(@NonNull android.os.VibrationEffect, @NonNull java.io.Writer) throws java.io.IOException, android.os.vibrator.persistence.VibrationXmlSerializer.SerializationFailedException; + method public static void serialize(@NonNull android.os.VibrationEffect, @NonNull java.io.Writer) throws java.io.IOException; } - public static final class VibrationXmlSerializer.SerializationFailedException extends java.lang.RuntimeException { + public static final class VibrationXmlSerializer.SerializationFailedException extends java.io.IOException { } } diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig index b01ffe5932fd..c73a422d931b 100644 --- a/core/java/android/os/vibrator/flags.aconfig +++ b/core/java/android/os/vibrator/flags.aconfig @@ -42,3 +42,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "haptics" + name: "vibration_xml_apis" + description: "Enabled System APIs for vibration effect XML parser and serializer" + bug: "347273158" + metadata { + purpose: PURPOSE_FEATURE + } +} diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java index a16d21eb87a3..e5543ab6c6f7 100644 --- a/core/java/android/os/vibrator/persistence/ParsedVibration.java +++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java @@ -16,31 +16,35 @@ package android.os.vibrator.persistence; +import static android.os.vibrator.Flags.FLAG_VIBRATION_XML_APIS; + +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.VibrationEffect; import android.os.Vibrator; import android.os.VibratorInfo; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Collections; import java.util.List; +import java.util.Objects; /** - * The result of parsing a serialized vibration, which can be define by one or more - * {@link VibrationEffect} and a resolution method. + * The result of parsing a serialized vibration. + * + * @see VibrationXmlParser * * @hide */ -@TestApi -@SuppressLint("UnflaggedApi") // @TestApi without associated feature. -public class ParsedVibration { +@TestApi // This was used in CTS before the flag was introduced. +@SystemApi +@FlaggedApi(FLAG_VIBRATION_XML_APIS) +public final class ParsedVibration { private final List<VibrationEffect> mEffects; /** @hide */ + @TestApi public ParsedVibration(@NonNull List<VibrationEffect> effects) { mEffects = effects; } @@ -49,40 +53,28 @@ public class ParsedVibration { public ParsedVibration(@NonNull VibrationEffect effect) { mEffects = List.of(effect); } + /** * Returns the first parsed vibration supported by {@code vibrator}, or {@code null} if none of * the parsed vibrations are supported. * * @hide */ - @TestApi + @TestApi // This was used in CTS before the flag was introduced. + @SystemApi + @FlaggedApi(FLAG_VIBRATION_XML_APIS) @Nullable public VibrationEffect resolve(@NonNull Vibrator vibrator) { return resolve(vibrator.getInfo()); } /** - * Returns the parsed vibrations for testing purposes. - * - * <p>Real callers should not use this method. Instead, they should resolve to a - * {@link VibrationEffect} via {@link #resolve(Vibrator)}. - * - * @hide - */ - @TestApi - @VisibleForTesting - @NonNull - public List<VibrationEffect> getVibrationEffects() { - return Collections.unmodifiableList(mEffects); - } - - /** * Same as {@link #resolve(Vibrator)}, but uses {@link VibratorInfo} instead for resolving. * * @hide */ @Nullable - public final VibrationEffect resolve(@NonNull VibratorInfo info) { + public VibrationEffect resolve(@NonNull VibratorInfo info) { for (int i = 0; i < mEffects.size(); i++) { VibrationEffect effect = mEffects.get(i); if (info.areVibrationFeaturesSupported(effect)) { @@ -91,4 +83,21 @@ public class ParsedVibration { } return null; } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ParsedVibration)) { + return false; + } + ParsedVibration other = (ParsedVibration) o; + return mEffects.equals(other.mEffects); + } + + @Override + public int hashCode() { + return Objects.hashCode(mEffects); + } } diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java index 7202d9a19c30..e2312e0c96c4 100644 --- a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java +++ b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java @@ -16,13 +16,15 @@ package android.os.vibrator.persistence; +import static android.os.vibrator.Flags.FLAG_VIBRATION_XML_APIS; + +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.VibrationEffect; -import android.util.Slog; import android.util.Xml; import com.android.internal.vibrator.persistence.VibrationEffectXmlParser; @@ -36,9 +38,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Reader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -116,10 +121,10 @@ import java.util.List; * * @hide */ -@TestApi -@SuppressLint("UnflaggedApi") // @TestApi without associated feature. +@TestApi // This was used in CTS before the flag was introduced. +@SystemApi +@FlaggedApi(FLAG_VIBRATION_XML_APIS) public final class VibrationXmlParser { - private static final String TAG = "VibrationXmlParser"; /** * The MIME type for a xml holding a vibration. @@ -168,93 +173,109 @@ public final class VibrationXmlParser { } /** - * Parses XML content from given input stream into a {@link VibrationEffect}. + * Parses XML content from given input stream into a {@link ParsedVibration}. + * + * <p>It supports both the "vibration-effect" and "vibration-select" root tags. + * <ul> + * <li>If "vibration-effect" is the root tag, the serialization provided should contain a + * valid serialization for a single vibration. + * <li>If "vibration-select" is the root tag, the serialization may contain one or more + * valid vibration serializations. + * </ul> + * + * <p>After parsing, it returns a {@link ParsedVibration} that opaquely represents the parsed + * vibration(s), and the caller can get a concrete {@link VibrationEffect} by resolving this + * result to a specific vibrator. + * + * <p>This parser fails with an exception if the content of the input stream does not follow the + * schema or has unsupported values. + * + * @return a {@link ParsedVibration} + * @throws IOException error reading from given {@link InputStream} or parsing the content. + * + * @hide + */ + @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced. + @SystemApi + @FlaggedApi(FLAG_VIBRATION_XML_APIS) + @NonNull + public static ParsedVibration parse(@NonNull InputStream inputStream) throws IOException { + return parseDocument(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + } + + /** + * Parses XML content from given input stream into a single {@link VibrationEffect}. * * <p>This method parses an XML content that contains a single, complete {@link VibrationEffect} - * serialization. As such, the root tag must be a "vibration" tag. + * serialization. As such, the root tag must be a "vibration-effect" tag. * - * <p>This parser fails silently and returns {@code null} if the content of the input stream - * does not follow the schema or has unsupported values. + * <p>This parser fails with an exception if the content of the input stream does not follow the + * schema or has unsupported values. * - * @return the {@link VibrationEffect} if parsed successfully, {@code null} otherwise. - * @throws IOException error reading from given {@link Reader} + * @return the parsed {@link VibrationEffect} + * @throws IOException error reading from given {@link InputStream} or parsing the content. * * @hide */ - @TestApi - @Nullable + @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced. + @SystemApi + @FlaggedApi(FLAG_VIBRATION_XML_APIS) + @NonNull + public static VibrationEffect parseVibrationEffect(@NonNull InputStream inputStream) + throws IOException { + return parseVibrationEffect(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + } + + /** + * Parses XML content from given {@link Reader} into a {@link VibrationEffect}. + * + * <p>Same as {@link #parseVibrationEffect(InputStream)}, but with a {@link Reader}. + * + * @hide + */ + @NonNull public static VibrationEffect parseVibrationEffect(@NonNull Reader reader) throws IOException { return parseVibrationEffect(reader, /* flags= */ 0); } /** - * Parses XML content from given input stream into a {@link VibrationEffect}. - * - * <p>This method parses an XML content that contains a single, complete {@link VibrationEffect} - * serialization. As such, the root tag must be a "vibration" tag. + * Parses XML content from given {@link Reader} into a {@link VibrationEffect}. * * <p>Same as {@link #parseVibrationEffect(Reader)}, with extra flags to control the parsing * behavior. * * @hide */ - @Nullable + @NonNull public static VibrationEffect parseVibrationEffect(@NonNull Reader reader, @Flags int flags) throws IOException { - try { - return parseDocumentInternal( - reader, flags, VibrationXmlParser::parseVibrationEffectInternal); - } catch (XmlParserException | XmlPullParserException e) { - Slog.w(TAG, "Error parsing vibration XML", e); - return null; - } + return parseDocumentInternal(reader, flags, + VibrationXmlParser::parseVibrationEffectInternal); } /** - * Parses XML content from given input stream into a {@link ParsedVibration}. + * Parses XML content from given {@link Reader} into a {@link ParsedVibration}. * - * <p>It supports both the "vibration" and "vibration-select" root tags. - * <ul> - * <li>If "vibration" is the root tag, the serialization provided through {@code reader} - * should contain a valid serialization for a single vibration. - * <li>If "vibration-select" is the root tag, the serialization may contain one or more - * valid vibration serializations. - * </ul> - * - * <p>After parsing, it returns a {@link ParsedVibration} that opaquely represents the parsed - * vibration(s), and the caller can get a concrete {@link VibrationEffect} by resolving this - * result to a specific vibrator. - * - * <p>This parser fails silently and returns {@code null} if the content of the input does not - * follow the schema or has unsupported values. - * - * @return a {@link ParsedVibration} - * @throws IOException error reading from given {@link Reader} + * <p>Same as {@link #parse(InputStream)}, but with a {@link Reader}. * * @hide */ - @TestApi - @Nullable + @NonNull public static ParsedVibration parseDocument(@NonNull Reader reader) throws IOException { return parseDocument(reader, /* flags= */ 0); } /** - * Parses XML content from given input stream into a {@link ParsedVibration}. + * Parses XML content from given {@link Reader} into a {@link ParsedVibration}. * * <p>Same as {@link #parseDocument(Reader)}, with extra flags to control the parsing behavior. * * @hide */ - @Nullable + @NonNull public static ParsedVibration parseDocument(@NonNull Reader reader, @Flags int flags) throws IOException { - try { - return parseDocumentInternal(reader, flags, VibrationXmlParser::parseElementInternal); - } catch (XmlParserException | XmlPullParserException e) { - Slog.w(TAG, "Error parsing vibration/vibration-select XML", e); - return null; - } + return parseDocumentInternal(reader, flags, VibrationXmlParser::parseElementInternal); } /** @@ -262,7 +283,7 @@ public final class VibrationXmlParser { * {@link ParsedVibration}. * * <p>Same as {@link #parseDocument(Reader, int)}, but, instead of parsing the full XML content, - * it takes a parser that points to either a <vibration-effect> or a <vibration-select> start + * it takes a parser that points to either a "vibration-effect" or a "vibration-select" start * tag. No other parser position, including start of document, is considered valid. * * <p>This method parses until an end "vibration-effect" or "vibration-select" tag (depending @@ -270,37 +291,22 @@ public final class VibrationXmlParser { * will point to the end tag. * * @throws IOException error parsing from given {@link TypedXmlPullParser}. - * @throws VibrationXmlParserException if the XML tag cannot be parsed into a - * {@link ParsedVibration}. The given {@code parser} might be pointing to a child XML tag - * that caused the parser failure. + * The given {@code parser} might be pointing to a child XML tag that caused the parser + * failure. * * @hide */ @NonNull public static ParsedVibration parseElement(@NonNull TypedXmlPullParser parser, @Flags int flags) - throws IOException, VibrationXmlParserException { + throws IOException { try { return parseElementInternal(parser, flags); } catch (XmlParserException e) { - throw new VibrationXmlParserException("Error parsing vibration-select.", e); - } - } - - /** - * Represents an error while parsing a vibration XML input. - * - * @hide - */ - public static final class VibrationXmlParserException extends Exception { - private VibrationXmlParserException(String message, Throwable cause) { - super(message, cause); - } - - private VibrationXmlParserException(String message) { - super(message); + throw new ParseFailedException(e); } } + @NonNull private static ParsedVibration parseElementInternal( @NonNull TypedXmlPullParser parser, @Flags int flags) throws IOException, XmlParserException { @@ -313,11 +319,12 @@ public final class VibrationXmlParser { case XmlConstants.TAG_VIBRATION_SELECT: return parseVibrationSelectInternal(parser, flags); default: - throw new XmlParserException( - "Unexpected tag name when parsing element: " + tagName); + throw new ParseFailedException( + "Unexpected tag " + tagName + " when parsing a vibration"); } } + @NonNull private static ParsedVibration parseVibrationSelectInternal( @NonNull TypedXmlPullParser parser, @Flags int flags) throws IOException, XmlParserException { @@ -332,7 +339,7 @@ public final class VibrationXmlParser { return new ParsedVibration(effects); } - /** Parses a single XML element for "vibration" tag into a {@link VibrationEffect}. */ + @NonNull private static VibrationEffect parseVibrationEffectInternal( @NonNull TypedXmlPullParser parser, @Flags int flags) throws IOException, XmlParserException { @@ -347,32 +354,60 @@ public final class VibrationXmlParser { * This method parses a whole XML document (provided through a {@link Reader}). The root tag is * parsed as per a provided {@link ElementParser}. */ + @NonNull private static <T> T parseDocumentInternal( @NonNull Reader reader, @Flags int flags, ElementParser<T> parseLogic) - throws IOException, XmlParserException, XmlPullParserException { - TypedXmlPullParser parser = Xml.newFastPullParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(reader); + throws IOException { + try { + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(reader); - // Ensure XML starts with a document start tag. - XmlReader.readDocumentStart(parser); + // Ensure XML starts with a document start tag. + XmlReader.readDocumentStart(parser); - // Parse root tag. - T result = parseLogic.parse(parser, flags); + // Parse root tag. + T result = parseLogic.parse(parser, flags); - // Ensure XML ends after root tag is consumed. - XmlReader.readDocumentEndTag(parser); + // Ensure XML ends after root tag is consumed. + XmlReader.readDocumentEndTag(parser); - return result; + return result; + } catch (XmlPullParserException e) { + throw new ParseFailedException("Error initializing XMLPullParser", e); + } catch (XmlParserException e) { + throw new ParseFailedException(e); + } } /** Encapsulate a logic to parse an XML element from an open parser. */ private interface ElementParser<T> { /** Parses a single XML element starting from the current position of the {@code parser}. */ + @NonNull T parse(@NonNull TypedXmlPullParser parser, @Flags int flags) throws IOException, XmlParserException; } + /** + * Represents an error while parsing a vibration XML input. + * + * @hide + */ + @TestApi + public static final class ParseFailedException extends IOException { + private ParseFailedException(String message) { + super(message); + } + + private ParseFailedException(XmlParserException parserException) { + this(parserException.getMessage(), parserException); + } + + private ParseFailedException(String message, Throwable cause) { + super(message, cause); + } + } + private VibrationXmlParser() { } } diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java index 2065d5d0a5a7..a26c6f434e15 100644 --- a/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java +++ b/core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java @@ -18,9 +18,7 @@ package android.os.vibrator.persistence; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SuppressLint; import android.annotation.TestApi; -import android.os.CombinedVibration; import android.os.VibrationEffect; import android.util.Xml; @@ -37,14 +35,13 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Serializes {@link CombinedVibration} and {@link VibrationEffect} instances to XML. + * Serializes {@link VibrationEffect} instances to XML. * * <p>This uses the same schema expected by the {@link VibrationXmlParser}. * * @hide */ @TestApi -@SuppressLint("UnflaggedApi") // @TestApi without associated feature. public final class VibrationXmlSerializer { /** @@ -80,20 +77,19 @@ public final class VibrationXmlSerializer { "http://xmlpull.org/v1/doc/features.html#indent-output"; /** - * Serializes a {@link VibrationEffect} to XML and writes output to given {@link Writer}. + * Serializes a {@link VibrationEffect} to XML and writes output to given {@link Writer} using + * UTF-8 encoding. * - * <p>This method will only write into the {@link Writer} if the effect can successfully - * be represented by the XML serialization. It will throw an exception otherwise. + * <p>This method will only write to the stream if the effect can successfully be represented by + * the XML serialization. It will throw an exception otherwise. * - * @throws SerializationFailedException serialization of input effect failed, no data was - * written into given {@link Writer}. - * @throws IOException error writing to given {@link Writer}. + * @throws IOException serialization of input effect failed or error writing to output stream. * * @hide */ @TestApi public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer) - throws SerializationFailedException, IOException { + throws IOException { serialize(effect, writer, /* flags= */ 0); } @@ -106,7 +102,7 @@ public final class VibrationXmlSerializer { * @hide */ public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer, - @Flags int flags) throws SerializationFailedException, IOException { + @Flags int flags) throws IOException { // Serialize effect first to fail early. XmlSerializedVibration<VibrationEffect> serializedVibration = toSerializedVibration(effect, flags); @@ -138,17 +134,16 @@ public final class VibrationXmlSerializer { } /** - * Exception thrown when a {@link VibrationEffect} instance serialization fails. + * Exception thrown when a {@link VibrationEffect} serialization fails. * * <p>The serialization can fail if a given vibration cannot be represented using the public - * format, or if it uses hidden APIs that are not supported for serialization (e.g. - * {@link VibrationEffect.WaveformBuilder}). + * format, or if it uses a non-public representation that is not supported for serialization. * * @hide */ @TestApi - public static final class SerializationFailedException extends RuntimeException { - SerializationFailedException(VibrationEffect effect, Throwable cause) { + public static final class SerializationFailedException extends IOException { + private SerializationFailedException(VibrationEffect effect, Throwable cause) { super("Serialization failed for vibration effect " + effect, cause); } } diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java index 94298dcd2c74..83a8f8f91ae6 100644 --- a/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java @@ -63,6 +63,34 @@ public class ParsedVibrationTest { } @Test + public void testEquals() { + assertThat(new ParsedVibration(List.of())).isEqualTo(new ParsedVibration(List.of())); + assertThat(new ParsedVibration(List.of())).isNotEqualTo(new ParsedVibration(mEffect1)); + assertThat(new ParsedVibration(mEffect1)).isEqualTo(new ParsedVibration(mEffect1)); + assertThat(new ParsedVibration(mEffect1)).isNotEqualTo(new ParsedVibration(mEffect2)); + assertThat(new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3))) + .isEqualTo(new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3))); + assertThat(new ParsedVibration(List.of(mEffect1, mEffect2))) + .isNotEqualTo(new ParsedVibration(List.of(mEffect2, mEffect1))); + } + + @Test + public void testHashCode() { + assertThat(new ParsedVibration(mEffect1).hashCode()) + .isEqualTo(new ParsedVibration(mEffect1).hashCode()); + assertThat(new ParsedVibration(mEffect1).hashCode()) + .isNotEqualTo(new ParsedVibration(mEffect2).hashCode()); + assertThat(new ParsedVibration(List.of()).hashCode()) + .isEqualTo(new ParsedVibration(List.of()).hashCode()); + assertThat(new ParsedVibration(List.of()).hashCode()) + .isNotEqualTo(new ParsedVibration(mEffect1).hashCode()); + assertThat(new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3)).hashCode()) + .isEqualTo(new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3)).hashCode()); + assertThat(new ParsedVibration(List.of(mEffect1, mEffect2)).hashCode()) + .isNotEqualTo(new ParsedVibration(List.of(mEffect2, mEffect1)).hashCode()); + } + + @Test public void testResolve_allUnsupportedVibrations() { when(mVibratorInfoMock.areVibrationFeaturesSupported(any())).thenReturn(false); @@ -91,21 +119,6 @@ public class ParsedVibrationTest { .isEqualTo(mEffect1); } - @Test - public void testGetVibrationEffects() { - ParsedVibration parsedVibration = - new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3)); - assertThat(parsedVibration.getVibrationEffects()) - .containsExactly(mEffect1, mEffect2, mEffect3) - .inOrder(); - - parsedVibration = new ParsedVibration(List.of(mEffect1)); - assertThat(parsedVibration.getVibrationEffects()).containsExactly(mEffect1); - - parsedVibration = new ParsedVibration(List.of()); - assertThat(parsedVibration.getVibrationEffects()).isEmpty(); - } - private Subject assertThatResolution( Vibrator vibrator, List<VibrationEffect> componentVibrations) { return assertThat(new ParsedVibration(componentVibrations).resolve(vibrator)); diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java index 7d8c53faaec4..bf9a820aca5c 100644 --- a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java @@ -37,9 +37,9 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.xmlpull.v1.XmlPullParser; -import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -74,18 +74,22 @@ public class VibrationEffectXmlSerializationTest { .addPrimitive(PRIMITIVE_CLICK) .addPrimitive(PRIMITIVE_TICK, 0.2497f) .compose(); - String xml = "<vibration-effect>" - + "<primitive-effect name=\"click\"/>" - + "<primitive-effect name=\"tick\" scale=\"0.2497\"/>" - + "</vibration-effect>"; + String xml = """ + <vibration-effect> + <primitive-effect name="click"/> + <primitive-effect name="tick" scale="0.2497"/> + </vibration-effect> + """.trim(); VibrationEffect effect2 = VibrationEffect.startComposition() .addPrimitive(PRIMITIVE_LOW_TICK, 1f, 356) .addPrimitive(PRIMITIVE_SPIN, 0.6364f, 7) .compose(); - String xml2 = "<vibration-effect>" - + "<primitive-effect name=\"low_tick\" delayMs=\"356\"/>" - + "<primitive-effect name=\"spin\" scale=\"0.6364\" delayMs=\"7\"/>" - + "</vibration-effect>"; + String xml2 = """ + <vibration-effect> + <primitive-effect name="low_tick" delayMs="356"/> + <primitive-effect name="spin" scale="0.6364" delayMs="7"/> + </vibration-effect> + """.trim(); TypedXmlPullParser parser = createXmlPullParser(xml); assertParseElementSucceeds(parser, effect); @@ -114,7 +118,12 @@ public class VibrationEffectXmlSerializationTest { assertEndOfDocument(parser); // Check when there is comment before the end tag. - xml = "<vibration-effect><primitive-effect name=\"tick\"/><!-- hi --></vibration-effect>"; + xml = """ + <vibration-effect> + <primitive-effect name="tick"/> + <!-- hi --> + </vibration-effect> + """.trim(); parser = createXmlPullParser(xml); assertParseElementSucceeds( parser, VibrationEffect.startComposition().addPrimitive(PRIMITIVE_TICK).compose()); @@ -128,18 +137,22 @@ public class VibrationEffectXmlSerializationTest { .addPrimitive(PRIMITIVE_CLICK) .addPrimitive(PRIMITIVE_TICK, 0.2497f) .compose(); - String vibrationXml1 = "<vibration-effect>" - + "<primitive-effect name=\"click\"/>" - + "<primitive-effect name=\"tick\" scale=\"0.2497\"/>" - + "</vibration-effect>"; + String vibrationXml1 = """ + <vibration-effect> + <primitive-effect name="click"/> + <primitive-effect name="tick" scale="0.2497"/> + </vibration-effect> + """.trim(); VibrationEffect effect2 = VibrationEffect.startComposition() .addPrimitive(PRIMITIVE_LOW_TICK, 1f, 356) .addPrimitive(PRIMITIVE_SPIN, 0.6364f, 7) .compose(); - String vibrationXml2 = "<vibration-effect>" - + "<primitive-effect name=\"low_tick\" delayMs=\"356\"/>" - + "<primitive-effect name=\"spin\" scale=\"0.6364\" delayMs=\"7\"/>" - + "</vibration-effect>"; + String vibrationXml2 = """ + <vibration-effect> + <primitive-effect name="low_tick" delayMs="356"/> + <primitive-effect name="spin" scale="0.6364" delayMs="7"/> + </vibration-effect> + """.trim(); String xml = "<vibration-select>" + vibrationXml1 + vibrationXml2 + "</vibration-select>"; TypedXmlPullParser parser = createXmlPullParser(xml); @@ -183,8 +196,11 @@ public class VibrationEffectXmlSerializationTest { @Test public void testParseElement_withHiddenApis_onlySucceedsWithFlag() throws Exception { // Check when the root tag is "vibration". - String xml = - "<vibration-effect><predefined-effect name=\"texture_tick\"/></vibration-effect>"; + String xml = """ + <vibration-effect> + <predefined-effect name="texture_tick"/> + </vibration-effect> + """.trim(); assertParseElementSucceeds(createXmlPullParser(xml), VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS, VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK)); @@ -199,131 +215,186 @@ public class VibrationEffectXmlSerializationTest { } @Test - public void testParseElement_badXml_throwsException() throws Exception { + public void testParseElement_badXml_throwsException() { // No "vibration-select" tag. - assertParseElementFails( - "<vibration-effect>rand text<primitive-effect name=\"click\"/></vibration-effect>"); - assertParseElementFails("<bad-tag><primitive-effect name=\"click\"/></vibration-effect>"); - assertParseElementFails("<primitive-effect name=\"click\"/></vibration-effect>"); - assertParseElementFails("<vibration-effect><primitive-effect name=\"click\"/>"); + assertParseElementFails(""" + <vibration-effect> + rand text + <primitive-effect name="click"/> + </vibration-effect> + """); + assertParseElementFails(""" + <bad-tag> + <primitive-effect name="click"/> + </vibration-effect> + """); + assertParseElementFails(""" + <primitive-effect name="click"/> + </vibration-effect> + """); + assertParseElementFails(""" + <vibration-effect> + <primitive-effect name="click"/> + """); // Incomplete XML. - assertParseElementFails("<vibration-select><primitive-effect name=\"click\"/>"); - assertParseElementFails("<vibration-select>" - + "<vibration-effect>" - + "<primitive-effect name=\"low_tick\" delayMs=\"356\"/>" - + "</vibration-effect>"); + assertParseElementFails(""" + <vibration-select> + <primitive-effect name="click"/> + """); + assertParseElementFails(""" + <vibration-select> + <vibration-effect> + <primitive-effect name="low_tick" delayMs="356"/> + </vibration-effect> + """); // Bad vibration XML. - assertParseElementFails("<vibration-select>" - + "<primitive-effect name=\"low_tick\" delayMs=\"356\"/>" - + "</vibration-effect>" - + "</vibration-select>"); + assertParseElementFails(""" + <vibration-select> + <primitive-effect name="low_tick" delayMs="356"/> + </vibration-effect> + </vibration-select> + """); // "vibration-select" tag should have no attributes. - assertParseElementFails("<vibration-select bad_attr=\"123\">" - + "<vibration-effect>" - + "<predefined-effect name=\"tick\"/>" - + "</vibration-effect>" - + "</vibration-select>"); + assertParseElementFails(""" + <vibration-select bad_attr="123"> + <vibration-effect> + <predefined-effect name="tick"/> + </vibration-effect> + </vibration-select> + """); } @Test - public void testPrimitives_allSucceed() throws IOException { + public void testInvalidEffects_allFail() { + // Invalid root tag. + String xml = """ + <vibration> + <predefined-effect name="click"/> + </vibration> + """; + + assertPublicApisParserFails(xml); + assertHiddenApisParserFails(xml); + + // Invalid effect name. + xml = """ + <vibration-effect> + <predefined-effect name="invalid"/> + </vibration-effect> + """; + + assertPublicApisParserFails(xml); + assertHiddenApisParserFails(xml); + } + + @Test + public void testVibrationSelectTag_onlyParseDocumentSucceeds() throws Exception { + VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); + String xml = """ + <vibration-select> + <vibration-effect><predefined-effect name="click"/></vibration-effect> + </vibration-select> + """; + + assertPublicApisParseDocumentSucceeds(xml, effect); + assertHiddenApisParseDocumentSucceeds(xml, effect); + + assertPublicApisParseVibrationEffectFails(xml); + assertHiddenApisParseVibrationEffectFails(xml); + } + + @Test + public void testPrimitives_allSucceed() throws Exception { VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(PRIMITIVE_CLICK) .addPrimitive(PRIMITIVE_TICK, 0.2497f) .addPrimitive(PRIMITIVE_LOW_TICK, 1f, 356) .addPrimitive(PRIMITIVE_SPIN, 0.6364f, 7) .compose(); - String xml = "<vibration-effect>" - + "<primitive-effect name=\"click\"/>" - + "<primitive-effect name=\"tick\" scale=\"0.2497\"/>" - + "<primitive-effect name=\"low_tick\" delayMs=\"356\"/>" - + "<primitive-effect name=\"spin\" scale=\"0.6364\" delayMs=\"7\"/>" - + "</vibration-effect>"; + String xml = """ + <vibration-effect> + <primitive-effect name="click"/> + <primitive-effect name="tick" scale="0.2497"/> + <primitive-effect name="low_tick" delayMs="356"/> + <primitive-effect name="spin" scale="0.6364" delayMs="7"/> + </vibration-effect> + """; assertPublicApisParserSucceeds(xml, effect); assertPublicApisSerializerSucceeds(effect, "click", "tick", "low_tick", "spin"); assertPublicApisRoundTrip(effect); - assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + assertHiddenApisParserSucceeds(xml, effect); assertHiddenApisSerializerSucceeds(effect, "click", "tick", "low_tick", "spin"); assertHiddenApisRoundTrip(effect); } @Test - public void testParseDocument_withVibrationSelectTag_withHiddenApis_onlySucceedsWithFlag() - throws Exception { - // Check when the root tag is "vibration-effect". - String xml = - "<vibration-effect><predefined-effect name=\"texture_tick\"/></vibration-effect>"; - assertParseDocumentSucceeds(xml, - VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS, - VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK)); - assertThat(parseDocument(xml, /* flags= */ 0)).isNull(); - - // Check when the root tag is "vibration-select". - xml = "<vibration-select>" + xml + "</vibration-select>"; - assertParseDocumentSucceeds(xml, - VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS, - VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK)); - assertThat(parseDocument(xml, /* flags= */ 0)).isNull(); - } - - @Test - public void testWaveforms_allSucceed() throws IOException { + public void testWaveforms_allSucceed() throws Exception { VibrationEffect effect = VibrationEffect.createWaveform(new long[]{123, 456, 789, 0}, new int[]{254, 1, 255, 0}, /* repeat= */ 0); - String xml = "<vibration-effect>" - + "<waveform-effect><repeating>" - + "<waveform-entry durationMs=\"123\" amplitude=\"254\"/>" - + "<waveform-entry durationMs=\"456\" amplitude=\"1\"/>" - + "<waveform-entry durationMs=\"789\" amplitude=\"255\"/>" - + "<waveform-entry durationMs=\"0\" amplitude=\"0\"/>" - + "</repeating></waveform-effect>" - + "</vibration-effect>"; + String xml = """ + <vibration-effect> + <waveform-effect> + <repeating> + <waveform-entry durationMs="123" amplitude="254"/> + <waveform-entry durationMs="456" amplitude="1"/> + <waveform-entry durationMs="789" amplitude="255"/> + <waveform-entry durationMs="0" amplitude="0"/> + </repeating> + </waveform-effect> + </vibration-effect> + """; assertPublicApisParserSucceeds(xml, effect); assertPublicApisSerializerSucceeds(effect, "123", "456", "789", "254", "1", "255", "0"); assertPublicApisRoundTrip(effect); - assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + assertHiddenApisParserSucceeds(xml, effect); assertHiddenApisSerializerSucceeds(effect, "123", "456", "789", "254", "1", "255", "0"); assertHiddenApisRoundTrip(effect); } @Test public void testPredefinedEffects_publicEffectsWithDefaultFallback_allSucceed() - throws IOException { + throws Exception { for (Map.Entry<String, Integer> entry : createPublicPredefinedEffectsMap().entrySet()) { VibrationEffect effect = VibrationEffect.get(entry.getValue()); - String xml = String.format( - "<vibration-effect><predefined-effect name=\"%s\"/></vibration-effect>", + String xml = String.format(""" + <vibration-effect> + <predefined-effect name="%s"/> + </vibration-effect> + """, entry.getKey()); assertPublicApisParserSucceeds(xml, effect); assertPublicApisSerializerSucceeds(effect, entry.getKey()); assertPublicApisRoundTrip(effect); - assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + assertHiddenApisParserSucceeds(xml, effect); assertHiddenApisSerializerSucceeds(effect, entry.getKey()); assertHiddenApisRoundTrip(effect); } } @Test - public void testPredefinedEffects_hiddenEffects_onlySucceedsWithFlag() throws IOException { + public void testPredefinedEffects_hiddenEffects_onlySucceedsWithFlag() throws Exception { for (Map.Entry<String, Integer> entry : createHiddenPredefinedEffectsMap().entrySet()) { VibrationEffect effect = VibrationEffect.get(entry.getValue()); - String xml = String.format( - "<vibration-effect><predefined-effect name=\"%s\"/></vibration-effect>", + String xml = String.format(""" + <vibration-effect> + <predefined-effect name="%s"/> + </vibration-effect> + """, entry.getKey()); assertPublicApisParserFails(xml); assertPublicApisSerializerFails(effect); - assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + assertHiddenApisParserSucceeds(xml, effect); assertHiddenApisSerializerSucceeds(effect, entry.getKey()); assertHiddenApisRoundTrip(effect); } @@ -331,33 +402,119 @@ public class VibrationEffectXmlSerializationTest { @Test public void testPredefinedEffects_allEffectsWithNonDefaultFallback_onlySucceedsWithFlag() - throws IOException { + throws Exception { for (Map.Entry<String, Integer> entry : createAllPredefinedEffectsMap().entrySet()) { boolean nonDefaultFallback = !PrebakedSegment.DEFAULT_SHOULD_FALLBACK; VibrationEffect effect = VibrationEffect.get(entry.getValue(), nonDefaultFallback); - String xml = String.format( - "<vibration-effect><predefined-effect name=\"%s\" fallback=\"%s\"/>" - + "</vibration-effect>", + String xml = String.format(""" + <vibration-effect> + <predefined-effect name="%s" fallback="%s"/> + </vibration-effect> + """, entry.getKey(), nonDefaultFallback); assertPublicApisParserFails(xml); assertPublicApisSerializerFails(effect); - assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + assertHiddenApisParserSucceeds(xml, effect); assertHiddenApisSerializerSucceeds(effect, entry.getKey()); assertHiddenApisRoundTrip(effect); } } - private void assertPublicApisParserFails(String xml) throws IOException { - assertThat(parseVibrationEffect(xml, /* flags= */ 0)).isNull(); + private void assertPublicApisParserFails(String xml) { + assertThrows("Expected parseVibrationEffect to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseVibrationEffect(xml, /* flags= */ 0)); + assertThrows("Expected parseDocument to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseDocument(xml, /* flags= */ 0)); + } + + private void assertPublicApisParseVibrationEffectFails(String xml) { + assertThrows("Expected parseVibrationEffect to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseVibrationEffect(xml, /* flags= */ 0)); } private void assertPublicApisParserSucceeds(String xml, VibrationEffect effect) - throws IOException { + throws Exception { + assertPublicApisParseDocumentSucceeds(xml, effect); + assertPublicApisParseVibrationEffectSucceeds(xml, effect); + } + + private void assertPublicApisParseDocumentSucceeds(String xml, VibrationEffect... effects) + throws Exception { + assertThat(parseDocument(xml, /* flags= */ 0)) + .isEqualTo(new ParsedVibration(Arrays.asList(effects))); + } + + private void assertPublicApisParseVibrationEffectSucceeds(String xml, VibrationEffect effect) + throws Exception { assertThat(parseVibrationEffect(xml, /* flags= */ 0)).isEqualTo(effect); } + private void assertHiddenApisParserFails(String xml) { + assertThrows("Expected parseVibrationEffect to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)); + assertThrows("Expected parseDocument to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseDocument(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)); + } + + private void assertHiddenApisParseVibrationEffectFails(String xml) { + assertThrows("Expected parseVibrationEffect to fail for " + xml, + VibrationXmlParser.ParseFailedException.class, + () -> parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)); + } + + private void assertHiddenApisParserSucceeds(String xml, VibrationEffect effect) + throws Exception { + assertHiddenApisParseDocumentSucceeds(xml, effect); + assertHiddenApisParseVibrationEffectSucceeds(xml, effect); + } + + private void assertHiddenApisParseDocumentSucceeds(String xml, VibrationEffect... effect) + throws Exception { + assertThat(parseDocument(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)) + .isEqualTo(new ParsedVibration(Arrays.asList(effect))); + } + + private void assertHiddenApisParseVibrationEffectSucceeds(String xml, VibrationEffect effect) + throws Exception { + assertThat(parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)) + .isEqualTo(effect); + } + + private void assertPublicApisSerializerFails(VibrationEffect effect) { + assertThrows("Expected serialization to fail for " + effect, + VibrationXmlSerializer.SerializationFailedException.class, + () -> serialize(effect)); + } + + private void assertPublicApisSerializerSucceeds(VibrationEffect effect, + String... expectedSegments) throws Exception { + assertSerializationContainsSegments(serialize(effect), expectedSegments); + } + + private void assertHiddenApisSerializerSucceeds(VibrationEffect effect, + String... expectedSegments) throws Exception { + assertSerializationContainsSegments( + serialize(effect, VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS), expectedSegments); + } + + private void assertPublicApisRoundTrip(VibrationEffect effect) throws Exception { + assertThat(parseVibrationEffect(serialize(effect, /* flags= */ 0), /* flags= */ 0)) + .isEqualTo(effect); + } + + private void assertHiddenApisRoundTrip(VibrationEffect effect) throws Exception { + String xml = serialize(effect, VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS); + assertThat(parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)) + .isEqualTo(effect); + } + private TypedXmlPullParser createXmlPullParser(String xml) throws Exception { TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); @@ -366,11 +523,6 @@ public class VibrationEffectXmlSerializationTest { return parser; } - private void assertParseDocumentSucceeds(String xml, int flags, VibrationEffect... effects) - throws Exception { - assertThat(parseDocument(xml, flags).getVibrationEffects()).containsExactly(effects); - } - /** * Asserts parsing vibration from an open TypedXmlPullParser succeeds, and that the parser * points to the end "vibration" or "vibration-select" tag. @@ -385,7 +537,8 @@ public class VibrationEffectXmlSerializationTest { String tagName = parser.getName(); assertThat(Set.of("vibration-effect", "vibration-select")).contains(tagName); - assertThat(parseElement(parser, flags).getVibrationEffects()).containsExactly(effects); + assertThat(parseElement(parser, flags)) + .isEqualTo(new ParsedVibration(Arrays.asList(effects))); assertThat(parser.getEventType()).isEqualTo(XmlPullParser.END_TAG); assertThat(parser.getName()).isEqualTo(tagName); } @@ -405,69 +558,40 @@ public class VibrationEffectXmlSerializationTest { assertThat(parser.getEventType()).isEqualTo(parser.END_DOCUMENT); } - private void assertHiddenApisParseVibrationEffectSucceeds(String xml, VibrationEffect effect) - throws IOException { - assertThat(parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)) - .isEqualTo(effect); - } - - private void assertPublicApisSerializerFails(VibrationEffect effect) { - assertThrows("Expected serialization to fail for " + effect, - VibrationXmlSerializer.SerializationFailedException.class, - () -> serialize(effect, /* flags= */ 0)); - } - private void assertParseElementFails(String xml) { assertThrows("Expected parsing to fail for " + xml, - VibrationXmlParser.VibrationXmlParserException.class, + VibrationXmlParser.ParseFailedException.class, () -> parseElement(createXmlPullParser(xml), /* flags= */ 0)); } - private void assertPublicApisSerializerSucceeds(VibrationEffect effect, - String... expectedSegments) throws IOException { - assertSerializationContainsSegments(serialize(effect, /* flags= */ 0), expectedSegments); - } - - private void assertHiddenApisSerializerSucceeds(VibrationEffect effect, - String... expectedSegments) throws IOException { - assertSerializationContainsSegments( - serialize(effect, VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS), expectedSegments); - } - private void assertSerializationContainsSegments(String xml, String[] expectedSegments) { for (String expectedSegment : expectedSegments) { assertThat(xml).contains(expectedSegment); } } - private void assertPublicApisRoundTrip(VibrationEffect effect) throws IOException { - assertThat(parseVibrationEffect(serialize(effect, /* flags= */ 0), /* flags= */ 0)) - .isEqualTo(effect); - } - - private void assertHiddenApisRoundTrip(VibrationEffect effect) throws IOException { - String xml = serialize(effect, VibrationXmlSerializer.FLAG_ALLOW_HIDDEN_APIS); - assertThat(parseVibrationEffect(xml, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS)) - .isEqualTo(effect); - } - private static VibrationEffect parseVibrationEffect( - String xml, @VibrationXmlParser.Flags int flags) throws IOException { + String xml, @VibrationXmlParser.Flags int flags) throws Exception { return VibrationXmlParser.parseVibrationEffect(new StringReader(xml), flags); } - private static ParsedVibration parseDocument(String xml, int flags) - throws IOException { + private static ParsedVibration parseDocument(String xml, int flags) throws Exception { return VibrationXmlParser.parseDocument(new StringReader(xml), flags); } private static ParsedVibration parseElement(TypedXmlPullParser parser, int flags) - throws IOException, VibrationXmlParser.VibrationXmlParserException { + throws Exception { return VibrationXmlParser.parseElement(parser, flags); } + private static String serialize(VibrationEffect effect) throws Exception { + StringWriter writer = new StringWriter(); + VibrationXmlSerializer.serialize(effect, writer); + return writer.toString(); + } + private static String serialize(VibrationEffect effect, @VibrationXmlSerializer.Flags int flags) - throws IOException { + throws Exception { StringWriter writer = new StringWriter(); VibrationXmlSerializer.serialize(effect, writer, flags); return writer.toString(); diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java index 9756094e5af0..503a7268d5d3 100644 --- a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java +++ b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java @@ -108,9 +108,9 @@ final class HapticFeedbackCustomization { throws CustomizationParserException, IOException { try { return loadVibrationsInternal(res, vibratorInfo); - } catch (VibrationXmlParser.VibrationXmlParserException - | XmlParserException - | XmlPullParserException e) { + } catch (VibrationXmlParser.ParseFailedException + | XmlParserException + | XmlPullParserException e) { throw new CustomizationParserException( "Error parsing haptic feedback customization file.", e); } @@ -121,7 +121,6 @@ final class HapticFeedbackCustomization { Resources res, VibratorInfo vibratorInfo) throws CustomizationParserException, IOException, - VibrationXmlParser.VibrationXmlParserException, XmlParserException, XmlPullParserException { if (!Flags.hapticFeedbackVibrationOemCustomizationEnabled()) { @@ -172,10 +171,6 @@ final class HapticFeedbackCustomization { ParsedVibration parsedVibration = VibrationXmlParser.parseElement( parser, VibrationXmlParser.FLAG_ALLOW_HIDDEN_APIS); - if (parsedVibration == null) { - throw new CustomizationParserException( - "Unable to parse vibration element for effect " + effectId); - } VibrationEffect effect = parsedVibration.resolve(vibratorInfo); if (effect != null) { if (effect.getDuration() == Long.MAX_VALUE) { diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 7f60dc443df7..5c15ccb55c65 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -2494,9 +2494,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { try { ParsedVibration parsedVibration = VibrationXmlParser.parseDocument(new StringReader(xml)); - if (parsedVibration == null) { - throw new IllegalArgumentException("Error parsing vibration XML " + xml); - } VibratorInfo combinedVibratorInfo = getCombinedVibratorInfo(); if (combinedVibratorInfo == null) { throw new IllegalStateException( |