summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt13
-rw-r--r--core/api/test-current.txt19
-rw-r--r--core/java/android/os/vibrator/flags.aconfig10
-rw-r--r--core/java/android/os/vibrator/persistence/ParsedVibration.java61
-rw-r--r--core/java/android/os/vibrator/persistence/VibrationXmlParser.java211
-rw-r--r--core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java29
-rw-r--r--core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java43
-rw-r--r--core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java402
-rw-r--r--services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java11
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java3
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(