Loading core/java/android/os/vibrator/persistence/VibrationXmlParser.java +48 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; Loading @@ -35,6 +36,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.Reader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Parses XML into a {@link VibrationEffect}. Loading @@ -43,10 +46,10 @@ import java.io.Reader; * * * Predefined vibration effects * * <pre>VibrationEffect * <pre> * {@code * <vibration> * <predefined-effect id="0" /> * <predefined-effect name="click" /> * </vibration> * } * </pre> Loading Loading @@ -75,10 +78,10 @@ import java.io.Reader; * <pre> * {@code * <vibration> * <primitive-effect id="1" /> * <primitive-effect id="2" scale="0.8" /> * <primitive-effect id="3" delayMs="50" /> * <primitive-effect id="2" scale="0.5" delayMs="100" /> * <primitive-effect name="click" /> * <primitive-effect name="slow_rise" scale="0.8" /> * <primitive-effect name="quick_fall" delayMs="50" /> * <primitive-effect name="tick" scale="0.5" delayMs="100" /> * </vibration> * } * </pre> Loading @@ -89,6 +92,24 @@ import java.io.Reader; public final class VibrationXmlParser { private static final String TAG = "VibrationXmlParser"; /** * Allows {@link VibrationEffect} instances created via non-public APIs to be parsed/serialized. * * <p>Note that the XML schema for non-public APIs is not backwards compatible. This is intended * for loading custom {@link VibrationEffect} configured per device and platform version, not * to be restored from old platform versions. * * @hide */ public static final int FLAG_ALLOW_HIDDEN_APIS = 1 << 0; // Same as VibrationXmlSerializer /** @hide */ @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_ALLOW_HIDDEN_APIS }) @Retention(RetentionPolicy.SOURCE) public @interface Flags {} /** * Parses XML content from given input stream into a {@link VibrationEffect}. * Loading @@ -103,6 +124,19 @@ public final class VibrationXmlParser { @TestApi @Nullable public static VibrationEffect parse(@NonNull Reader reader) throws IOException { return parse(reader, /* flags= */ 0); } /** * Parses XML content from given input stream into a {@link VibrationEffect}. * * <p>Same as {@link #parse(Reader)}, with extra flags to control the parsing behavior. * * @hide */ @Nullable public static VibrationEffect parse(@NonNull Reader reader, @Flags int flags) throws IOException { TypedXmlPullParser parser = Xml.newFastPullParser(); try { Loading @@ -116,14 +150,19 @@ public final class VibrationXmlParser { // Ensure XML starts with expected root tag. XmlReader.readDocumentStartTag(parser, XmlConstants.TAG_VIBRATION); int parserFlags = 0; if ((flags & FLAG_ALLOW_HIDDEN_APIS) != 0) { parserFlags |= XmlConstants.FLAG_ALLOW_HIDDEN_APIS; } // Parse root tag as a vibration effect. XmlSerializedVibration<VibrationEffect> serializable = VibrationEffectXmlParser.parseTag(parser); XmlSerializedVibration<VibrationEffect> serializedVibration = VibrationEffectXmlParser.parseTag(parser, parserFlags); // Ensure XML ends after root tag is consumed. XmlReader.readDocumentEndTag(parser); return serializable.deserialize(); return serializedVibration.deserialize(); } catch (XmlParserException e) { Slog.w(TAG, "Error parsing vibration XML", e); return null; Loading core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java +69 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; import android.os.CombinedVibration; Loading @@ -23,6 +24,7 @@ import android.os.VibrationEffect; import android.util.Xml; import com.android.internal.vibrator.persistence.VibrationEffectXmlSerializer; import com.android.internal.vibrator.persistence.XmlConstants; import com.android.internal.vibrator.persistence.XmlSerializedVibration; import com.android.internal.vibrator.persistence.XmlSerializerException; import com.android.internal.vibrator.persistence.XmlValidator; Loading @@ -30,6 +32,8 @@ import com.android.modules.utils.TypedXmlSerializer; import java.io.IOException; import java.io.Writer; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Serializes {@link CombinedVibration} and {@link VibrationEffect} instances to XML. Loading @@ -40,10 +44,37 @@ import java.io.Writer; */ @TestApi public final class VibrationXmlSerializer { private static final String TAG = "VibrationXmlSerializer"; private static final String SERIALIZER_ENCODING = Xml.Encoding.UTF_8.name(); private static final String SERIALIZER_FEATURE_INDENT_OUTPUT = /** * Allows {@link VibrationEffect} instances created via non-public APIs to be parsed/serialized. * * <p>Note that the XML schema for non-public APIs is not backwards compatible. This is intended * for loading custom {@link VibrationEffect} configured per device and platform version, not * to be restored from old platform versions or from different devices. * * @hide */ public static final int FLAG_ALLOW_HIDDEN_APIS = 1 << 0; /** * Writes a more human-readable output XML. * * <p>This will be less compact as it includes extra whitespace for things like indentation. * * @hide */ public static final int FLAG_PRETTY_PRINT = 1 << 1; /** @hide */ @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_PRETTY_PRINT, FLAG_ALLOW_HIDDEN_APIS }) @Retention(RetentionPolicy.SOURCE) public @interface Flags {} private static final String XML_ENCODING = Xml.Encoding.UTF_8.name(); private static final String XML_FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output"; /** Loading @@ -62,21 +93,47 @@ public final class VibrationXmlSerializer { @TestApi public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer) throws SerializationFailedException, IOException { XmlSerializedVibration<VibrationEffect> serializableEffect; serialize(effect, writer, /* flags= */ 0); } /** * Serializes a {@link VibrationEffect} to XML and writes output to given {@link Writer}. * * <p>Same as {@link #serialize(VibrationEffect, Writer)}, with extra flags to control the * serialization behavior. * * @hide */ public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer, @Flags int flags) throws SerializationFailedException, IOException { // Serialize effect first to fail early. XmlSerializedVibration<VibrationEffect> serializedVibration = toSerializedVibration(effect, flags); TypedXmlSerializer xmlSerializer = Xml.newFastSerializer(); xmlSerializer.setFeature(XML_FEATURE_INDENT_OUTPUT, (flags & FLAG_PRETTY_PRINT) != 0); xmlSerializer.setOutput(writer); xmlSerializer.startDocument(XML_ENCODING, /* standalone= */ false); serializedVibration.write(xmlSerializer); xmlSerializer.endDocument(); } private static XmlSerializedVibration<VibrationEffect> toSerializedVibration( VibrationEffect effect, @Flags int flags) throws SerializationFailedException { XmlSerializedVibration<VibrationEffect> serializedVibration; int serializerFlags = 0; if ((flags & FLAG_ALLOW_HIDDEN_APIS) != 0) { serializerFlags |= XmlConstants.FLAG_ALLOW_HIDDEN_APIS; } try { serializableEffect = VibrationEffectXmlSerializer.serialize(effect); XmlValidator.checkSerializedVibration(serializableEffect, effect); serializedVibration = VibrationEffectXmlSerializer.serialize(effect, serializerFlags); XmlValidator.checkSerializedVibration(serializedVibration, effect); } catch (XmlSerializerException e) { // Serialization failed or created incomplete representation, fail before writing. throw new SerializationFailedException(effect, e); } TypedXmlSerializer xmlSerializer = Xml.newFastSerializer(); xmlSerializer.setFeature(SERIALIZER_FEATURE_INDENT_OUTPUT, false); xmlSerializer.setOutput(writer); xmlSerializer.startDocument(SERIALIZER_ENCODING, /* standalone= */ false); serializableEffect.write(xmlSerializer); xmlSerializer.endDocument(); return serializedVibration; } /** Loading core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java +3 −3 Original line number Diff line number Diff line Loading @@ -78,9 +78,9 @@ final class SerializedCompositionPrimitive implements SerializedSegment { @Override public String toString() { return "SerializedCompositionPrimitive{" + "primitiveName=" + mPrimitiveName + ", primitiveScale=" + mPrimitiveScale + ", primitiveDelayMs=" + mPrimitiveDelayMs + "name=" + mPrimitiveName + ", scale=" + mPrimitiveScale + ", delayMs=" + mPrimitiveDelayMs + '}'; } Loading core/java/com/android/internal/vibrator/persistence/SerializedPredefinedEffect.java +36 −23 Original line number Diff line number Diff line Loading @@ -16,13 +16,14 @@ package com.android.internal.vibrator.persistence; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_FALLBACK; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME; import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PREDEFINED_EFFECT; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.VibrationEffect; import android.os.vibrator.PrebakedSegment; import com.android.internal.vibrator.persistence.SerializedVibrationEffect.SerializedSegment; import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName; Loading @@ -33,34 +34,41 @@ import java.io.IOException; /** * Serialized representation of a predefined effect created via * {@link VibrationEffect#createPredefined(int)}. * {@link VibrationEffect#get(int, boolean)}. * * @hide */ final class SerializedPredefinedEffect implements SerializedSegment { @NonNull private final PredefinedEffectName mEffectName; private final boolean mShouldFallback; SerializedPredefinedEffect(PredefinedEffectName effectName) { SerializedPredefinedEffect(PredefinedEffectName effectName, boolean shouldFallback) { mEffectName = effectName; mShouldFallback = shouldFallback; } @Override public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) { composition.addEffect(VibrationEffect.createPredefined(mEffectName.getEffectId())); composition.addEffect(VibrationEffect.get(mEffectName.getEffectId(), mShouldFallback)); } @Override public void write(@NonNull TypedXmlSerializer serializer) throws IOException { serializer.startTag(NAMESPACE, TAG_PREDEFINED_EFFECT); serializer.attribute(NAMESPACE, ATTRIBUTE_NAME, mEffectName.toString()); if (mShouldFallback != PrebakedSegment.DEFAULT_SHOULD_FALLBACK) { serializer.attributeBoolean(NAMESPACE, ATTRIBUTE_FALLBACK, mShouldFallback); } serializer.endTag(NAMESPACE, TAG_PREDEFINED_EFFECT); } @Override public String toString() { return "SerializedPredefinedEffect{" + "effectName=" + mEffectName + "name=" + mEffectName + ", fallback=" + mShouldFallback + '}'; } Loading @@ -68,31 +76,36 @@ final class SerializedPredefinedEffect implements SerializedSegment { static final class Parser { @NonNull static SerializedPredefinedEffect parseNext(@NonNull TypedXmlPullParser parser) throws XmlParserException, IOException { static SerializedPredefinedEffect parseNext(@NonNull TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { XmlValidator.checkStartTag(parser, TAG_PREDEFINED_EFFECT); XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME); PredefinedEffectName effectName = parseEffectName( parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME)); // Consume tag XmlReader.readEndTag(parser); return new SerializedPredefinedEffect(effectName); boolean allowHidden = (flags & XmlConstants.FLAG_ALLOW_HIDDEN_APIS) != 0; if (allowHidden) { XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME, ATTRIBUTE_FALLBACK); } else { XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME); } @NonNull private static PredefinedEffectName parseEffectName(@Nullable String name) throws XmlParserException { if (name == null) { String nameAttr = parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME); if (nameAttr == null) { throw new XmlParserException("Missing predefined effect name"); } PredefinedEffectName effectName = PredefinedEffectName.findByName(name); PredefinedEffectName effectName = PredefinedEffectName.findByName(nameAttr, flags); if (effectName == null) { throw new XmlParserException("Unexpected predefined effect name " + name); throw new XmlParserException("Unexpected predefined effect name " + nameAttr); } return effectName; boolean defaultFallback = PrebakedSegment.DEFAULT_SHOULD_FALLBACK; boolean fallback = allowHidden ? parser.getAttributeBoolean(NAMESPACE, ATTRIBUTE_FALLBACK, defaultFallback) : defaultFallback; // Consume tag XmlReader.readEndTag(parser); return new SerializedPredefinedEffect(effectName, fallback); } } } core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java +18 −21 Original line number Diff line number Diff line Loading @@ -34,16 +34,18 @@ import java.util.List; /** * Parser implementation for {@link VibrationEffect}. * * <p>This parser supports the schema defined by services/core/xsd/vibrator/vibration/vibration.xsd. * * <p>This parser does not support effects created with {@link VibrationEffect.WaveformBuilder} nor * {@link VibrationEffect.Composition#addEffect(VibrationEffect)}. It only supports vibration * effects defined as: * * * Predefined vibration effects * * <pre>VibrationEffect * <pre> * {@code * <vibration> * <predefined-effect id="0" /> * <predefined-effect name="click" /> * </vibration> * } * </pre> Loading Loading @@ -72,8 +74,8 @@ import java.util.List; * <pre> * {@code * <vibration> * <primitive-effect id="1" /> * <primitive-effect id="2" scale="0.5" delayMs="100" /> * <primitive-effect name="click" /> * <primitive-effect name="tick" scale="0.5" delayMs="100" /> * </vibration> * } * </pre> Loading @@ -90,10 +92,12 @@ public class VibrationEffectXmlParser { */ @NonNull public static XmlSerializedVibration<VibrationEffect> parseTag( @NonNull TypedXmlPullParser parser) throws XmlParserException, IOException { @NonNull TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { XmlValidator.checkStartTag(parser, TAG_VIBRATION); XmlValidator.checkTagHasNoUnexpectedAttributes(parser); return parseVibrationContent(parser); return parseVibrationContent(parser, flags); } /** Loading @@ -103,8 +107,8 @@ public class VibrationEffectXmlParser { * <p>This can be reused for reading a vibration from an XML root tag or from within a combined * vibration, but it should always be called from places that validates the top level tag. */ static SerializedVibrationEffect parseVibrationContent(TypedXmlPullParser parser) throws XmlParserException, IOException { static SerializedVibrationEffect parseVibrationContent(TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { String vibrationTagName = parser.getName(); int vibrationTagDepth = parser.getDepth(); Loading @@ -117,11 +121,15 @@ public class VibrationEffectXmlParser { switch (parser.getName()) { case TAG_PREDEFINED_EFFECT: serializedVibration = new SerializedVibrationEffect( SerializedPredefinedEffect.Parser.parseNext(parser)); SerializedPredefinedEffect.Parser.parseNext(parser, flags)); break; case TAG_PRIMITIVE_EFFECT: List<SerializedSegment> primitives = new ArrayList<>(); do { // First primitive tag already open primitives.add(SerializedCompositionPrimitive.Parser.parseNext(parser)); } while (XmlReader.readNextTagWithin(parser, vibrationTagDepth)); serializedVibration = new SerializedVibrationEffect( parsePrimitiveList(parser, vibrationTagDepth)); primitives.toArray(new SerializedSegment[primitives.size()])); break; case TAG_WAVEFORM_EFFECT: serializedVibration = new SerializedVibrationEffect( Loading @@ -137,15 +145,4 @@ public class VibrationEffectXmlParser { return serializedVibration; } private static SerializedSegment[] parsePrimitiveList( TypedXmlPullParser parser, int outerDepth) throws XmlParserException, IOException { List<SerializedSegment> segments = new ArrayList<>(); do { // First primitive tag already open segments.add(SerializedCompositionPrimitive.Parser.parseNext(parser)); } while (XmlReader.readNextTagWithin(parser, outerDepth)); return segments.toArray(new SerializedSegment[segments.size()]); } } Loading
core/java/android/os/vibrator/persistence/VibrationXmlParser.java +48 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; Loading @@ -35,6 +36,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.Reader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Parses XML into a {@link VibrationEffect}. Loading @@ -43,10 +46,10 @@ import java.io.Reader; * * * Predefined vibration effects * * <pre>VibrationEffect * <pre> * {@code * <vibration> * <predefined-effect id="0" /> * <predefined-effect name="click" /> * </vibration> * } * </pre> Loading Loading @@ -75,10 +78,10 @@ import java.io.Reader; * <pre> * {@code * <vibration> * <primitive-effect id="1" /> * <primitive-effect id="2" scale="0.8" /> * <primitive-effect id="3" delayMs="50" /> * <primitive-effect id="2" scale="0.5" delayMs="100" /> * <primitive-effect name="click" /> * <primitive-effect name="slow_rise" scale="0.8" /> * <primitive-effect name="quick_fall" delayMs="50" /> * <primitive-effect name="tick" scale="0.5" delayMs="100" /> * </vibration> * } * </pre> Loading @@ -89,6 +92,24 @@ import java.io.Reader; public final class VibrationXmlParser { private static final String TAG = "VibrationXmlParser"; /** * Allows {@link VibrationEffect} instances created via non-public APIs to be parsed/serialized. * * <p>Note that the XML schema for non-public APIs is not backwards compatible. This is intended * for loading custom {@link VibrationEffect} configured per device and platform version, not * to be restored from old platform versions. * * @hide */ public static final int FLAG_ALLOW_HIDDEN_APIS = 1 << 0; // Same as VibrationXmlSerializer /** @hide */ @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_ALLOW_HIDDEN_APIS }) @Retention(RetentionPolicy.SOURCE) public @interface Flags {} /** * Parses XML content from given input stream into a {@link VibrationEffect}. * Loading @@ -103,6 +124,19 @@ public final class VibrationXmlParser { @TestApi @Nullable public static VibrationEffect parse(@NonNull Reader reader) throws IOException { return parse(reader, /* flags= */ 0); } /** * Parses XML content from given input stream into a {@link VibrationEffect}. * * <p>Same as {@link #parse(Reader)}, with extra flags to control the parsing behavior. * * @hide */ @Nullable public static VibrationEffect parse(@NonNull Reader reader, @Flags int flags) throws IOException { TypedXmlPullParser parser = Xml.newFastPullParser(); try { Loading @@ -116,14 +150,19 @@ public final class VibrationXmlParser { // Ensure XML starts with expected root tag. XmlReader.readDocumentStartTag(parser, XmlConstants.TAG_VIBRATION); int parserFlags = 0; if ((flags & FLAG_ALLOW_HIDDEN_APIS) != 0) { parserFlags |= XmlConstants.FLAG_ALLOW_HIDDEN_APIS; } // Parse root tag as a vibration effect. XmlSerializedVibration<VibrationEffect> serializable = VibrationEffectXmlParser.parseTag(parser); XmlSerializedVibration<VibrationEffect> serializedVibration = VibrationEffectXmlParser.parseTag(parser, parserFlags); // Ensure XML ends after root tag is consumed. XmlReader.readDocumentEndTag(parser); return serializable.deserialize(); return serializedVibration.deserialize(); } catch (XmlParserException e) { Slog.w(TAG, "Error parsing vibration XML", e); return null; Loading
core/java/android/os/vibrator/persistence/VibrationXmlSerializer.java +69 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os.vibrator.persistence; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; import android.os.CombinedVibration; Loading @@ -23,6 +24,7 @@ import android.os.VibrationEffect; import android.util.Xml; import com.android.internal.vibrator.persistence.VibrationEffectXmlSerializer; import com.android.internal.vibrator.persistence.XmlConstants; import com.android.internal.vibrator.persistence.XmlSerializedVibration; import com.android.internal.vibrator.persistence.XmlSerializerException; import com.android.internal.vibrator.persistence.XmlValidator; Loading @@ -30,6 +32,8 @@ import com.android.modules.utils.TypedXmlSerializer; import java.io.IOException; import java.io.Writer; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Serializes {@link CombinedVibration} and {@link VibrationEffect} instances to XML. Loading @@ -40,10 +44,37 @@ import java.io.Writer; */ @TestApi public final class VibrationXmlSerializer { private static final String TAG = "VibrationXmlSerializer"; private static final String SERIALIZER_ENCODING = Xml.Encoding.UTF_8.name(); private static final String SERIALIZER_FEATURE_INDENT_OUTPUT = /** * Allows {@link VibrationEffect} instances created via non-public APIs to be parsed/serialized. * * <p>Note that the XML schema for non-public APIs is not backwards compatible. This is intended * for loading custom {@link VibrationEffect} configured per device and platform version, not * to be restored from old platform versions or from different devices. * * @hide */ public static final int FLAG_ALLOW_HIDDEN_APIS = 1 << 0; /** * Writes a more human-readable output XML. * * <p>This will be less compact as it includes extra whitespace for things like indentation. * * @hide */ public static final int FLAG_PRETTY_PRINT = 1 << 1; /** @hide */ @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_PRETTY_PRINT, FLAG_ALLOW_HIDDEN_APIS }) @Retention(RetentionPolicy.SOURCE) public @interface Flags {} private static final String XML_ENCODING = Xml.Encoding.UTF_8.name(); private static final String XML_FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output"; /** Loading @@ -62,21 +93,47 @@ public final class VibrationXmlSerializer { @TestApi public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer) throws SerializationFailedException, IOException { XmlSerializedVibration<VibrationEffect> serializableEffect; serialize(effect, writer, /* flags= */ 0); } /** * Serializes a {@link VibrationEffect} to XML and writes output to given {@link Writer}. * * <p>Same as {@link #serialize(VibrationEffect, Writer)}, with extra flags to control the * serialization behavior. * * @hide */ public static void serialize(@NonNull VibrationEffect effect, @NonNull Writer writer, @Flags int flags) throws SerializationFailedException, IOException { // Serialize effect first to fail early. XmlSerializedVibration<VibrationEffect> serializedVibration = toSerializedVibration(effect, flags); TypedXmlSerializer xmlSerializer = Xml.newFastSerializer(); xmlSerializer.setFeature(XML_FEATURE_INDENT_OUTPUT, (flags & FLAG_PRETTY_PRINT) != 0); xmlSerializer.setOutput(writer); xmlSerializer.startDocument(XML_ENCODING, /* standalone= */ false); serializedVibration.write(xmlSerializer); xmlSerializer.endDocument(); } private static XmlSerializedVibration<VibrationEffect> toSerializedVibration( VibrationEffect effect, @Flags int flags) throws SerializationFailedException { XmlSerializedVibration<VibrationEffect> serializedVibration; int serializerFlags = 0; if ((flags & FLAG_ALLOW_HIDDEN_APIS) != 0) { serializerFlags |= XmlConstants.FLAG_ALLOW_HIDDEN_APIS; } try { serializableEffect = VibrationEffectXmlSerializer.serialize(effect); XmlValidator.checkSerializedVibration(serializableEffect, effect); serializedVibration = VibrationEffectXmlSerializer.serialize(effect, serializerFlags); XmlValidator.checkSerializedVibration(serializedVibration, effect); } catch (XmlSerializerException e) { // Serialization failed or created incomplete representation, fail before writing. throw new SerializationFailedException(effect, e); } TypedXmlSerializer xmlSerializer = Xml.newFastSerializer(); xmlSerializer.setFeature(SERIALIZER_FEATURE_INDENT_OUTPUT, false); xmlSerializer.setOutput(writer); xmlSerializer.startDocument(SERIALIZER_ENCODING, /* standalone= */ false); serializableEffect.write(xmlSerializer); xmlSerializer.endDocument(); return serializedVibration; } /** Loading
core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java +3 −3 Original line number Diff line number Diff line Loading @@ -78,9 +78,9 @@ final class SerializedCompositionPrimitive implements SerializedSegment { @Override public String toString() { return "SerializedCompositionPrimitive{" + "primitiveName=" + mPrimitiveName + ", primitiveScale=" + mPrimitiveScale + ", primitiveDelayMs=" + mPrimitiveDelayMs + "name=" + mPrimitiveName + ", scale=" + mPrimitiveScale + ", delayMs=" + mPrimitiveDelayMs + '}'; } Loading
core/java/com/android/internal/vibrator/persistence/SerializedPredefinedEffect.java +36 −23 Original line number Diff line number Diff line Loading @@ -16,13 +16,14 @@ package com.android.internal.vibrator.persistence; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_FALLBACK; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME; import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PREDEFINED_EFFECT; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.VibrationEffect; import android.os.vibrator.PrebakedSegment; import com.android.internal.vibrator.persistence.SerializedVibrationEffect.SerializedSegment; import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName; Loading @@ -33,34 +34,41 @@ import java.io.IOException; /** * Serialized representation of a predefined effect created via * {@link VibrationEffect#createPredefined(int)}. * {@link VibrationEffect#get(int, boolean)}. * * @hide */ final class SerializedPredefinedEffect implements SerializedSegment { @NonNull private final PredefinedEffectName mEffectName; private final boolean mShouldFallback; SerializedPredefinedEffect(PredefinedEffectName effectName) { SerializedPredefinedEffect(PredefinedEffectName effectName, boolean shouldFallback) { mEffectName = effectName; mShouldFallback = shouldFallback; } @Override public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) { composition.addEffect(VibrationEffect.createPredefined(mEffectName.getEffectId())); composition.addEffect(VibrationEffect.get(mEffectName.getEffectId(), mShouldFallback)); } @Override public void write(@NonNull TypedXmlSerializer serializer) throws IOException { serializer.startTag(NAMESPACE, TAG_PREDEFINED_EFFECT); serializer.attribute(NAMESPACE, ATTRIBUTE_NAME, mEffectName.toString()); if (mShouldFallback != PrebakedSegment.DEFAULT_SHOULD_FALLBACK) { serializer.attributeBoolean(NAMESPACE, ATTRIBUTE_FALLBACK, mShouldFallback); } serializer.endTag(NAMESPACE, TAG_PREDEFINED_EFFECT); } @Override public String toString() { return "SerializedPredefinedEffect{" + "effectName=" + mEffectName + "name=" + mEffectName + ", fallback=" + mShouldFallback + '}'; } Loading @@ -68,31 +76,36 @@ final class SerializedPredefinedEffect implements SerializedSegment { static final class Parser { @NonNull static SerializedPredefinedEffect parseNext(@NonNull TypedXmlPullParser parser) throws XmlParserException, IOException { static SerializedPredefinedEffect parseNext(@NonNull TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { XmlValidator.checkStartTag(parser, TAG_PREDEFINED_EFFECT); XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME); PredefinedEffectName effectName = parseEffectName( parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME)); // Consume tag XmlReader.readEndTag(parser); return new SerializedPredefinedEffect(effectName); boolean allowHidden = (flags & XmlConstants.FLAG_ALLOW_HIDDEN_APIS) != 0; if (allowHidden) { XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME, ATTRIBUTE_FALLBACK); } else { XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_NAME); } @NonNull private static PredefinedEffectName parseEffectName(@Nullable String name) throws XmlParserException { if (name == null) { String nameAttr = parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME); if (nameAttr == null) { throw new XmlParserException("Missing predefined effect name"); } PredefinedEffectName effectName = PredefinedEffectName.findByName(name); PredefinedEffectName effectName = PredefinedEffectName.findByName(nameAttr, flags); if (effectName == null) { throw new XmlParserException("Unexpected predefined effect name " + name); throw new XmlParserException("Unexpected predefined effect name " + nameAttr); } return effectName; boolean defaultFallback = PrebakedSegment.DEFAULT_SHOULD_FALLBACK; boolean fallback = allowHidden ? parser.getAttributeBoolean(NAMESPACE, ATTRIBUTE_FALLBACK, defaultFallback) : defaultFallback; // Consume tag XmlReader.readEndTag(parser); return new SerializedPredefinedEffect(effectName, fallback); } } }
core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java +18 −21 Original line number Diff line number Diff line Loading @@ -34,16 +34,18 @@ import java.util.List; /** * Parser implementation for {@link VibrationEffect}. * * <p>This parser supports the schema defined by services/core/xsd/vibrator/vibration/vibration.xsd. * * <p>This parser does not support effects created with {@link VibrationEffect.WaveformBuilder} nor * {@link VibrationEffect.Composition#addEffect(VibrationEffect)}. It only supports vibration * effects defined as: * * * Predefined vibration effects * * <pre>VibrationEffect * <pre> * {@code * <vibration> * <predefined-effect id="0" /> * <predefined-effect name="click" /> * </vibration> * } * </pre> Loading Loading @@ -72,8 +74,8 @@ import java.util.List; * <pre> * {@code * <vibration> * <primitive-effect id="1" /> * <primitive-effect id="2" scale="0.5" delayMs="100" /> * <primitive-effect name="click" /> * <primitive-effect name="tick" scale="0.5" delayMs="100" /> * </vibration> * } * </pre> Loading @@ -90,10 +92,12 @@ public class VibrationEffectXmlParser { */ @NonNull public static XmlSerializedVibration<VibrationEffect> parseTag( @NonNull TypedXmlPullParser parser) throws XmlParserException, IOException { @NonNull TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { XmlValidator.checkStartTag(parser, TAG_VIBRATION); XmlValidator.checkTagHasNoUnexpectedAttributes(parser); return parseVibrationContent(parser); return parseVibrationContent(parser, flags); } /** Loading @@ -103,8 +107,8 @@ public class VibrationEffectXmlParser { * <p>This can be reused for reading a vibration from an XML root tag or from within a combined * vibration, but it should always be called from places that validates the top level tag. */ static SerializedVibrationEffect parseVibrationContent(TypedXmlPullParser parser) throws XmlParserException, IOException { static SerializedVibrationEffect parseVibrationContent(TypedXmlPullParser parser, @XmlConstants.Flags int flags) throws XmlParserException, IOException { String vibrationTagName = parser.getName(); int vibrationTagDepth = parser.getDepth(); Loading @@ -117,11 +121,15 @@ public class VibrationEffectXmlParser { switch (parser.getName()) { case TAG_PREDEFINED_EFFECT: serializedVibration = new SerializedVibrationEffect( SerializedPredefinedEffect.Parser.parseNext(parser)); SerializedPredefinedEffect.Parser.parseNext(parser, flags)); break; case TAG_PRIMITIVE_EFFECT: List<SerializedSegment> primitives = new ArrayList<>(); do { // First primitive tag already open primitives.add(SerializedCompositionPrimitive.Parser.parseNext(parser)); } while (XmlReader.readNextTagWithin(parser, vibrationTagDepth)); serializedVibration = new SerializedVibrationEffect( parsePrimitiveList(parser, vibrationTagDepth)); primitives.toArray(new SerializedSegment[primitives.size()])); break; case TAG_WAVEFORM_EFFECT: serializedVibration = new SerializedVibrationEffect( Loading @@ -137,15 +145,4 @@ public class VibrationEffectXmlParser { return serializedVibration; } private static SerializedSegment[] parsePrimitiveList( TypedXmlPullParser parser, int outerDepth) throws XmlParserException, IOException { List<SerializedSegment> segments = new ArrayList<>(); do { // First primitive tag already open segments.add(SerializedCompositionPrimitive.Parser.parseNext(parser)); } while (XmlReader.readNextTagWithin(parser, outerDepth)); return segments.toArray(new SerializedSegment[segments.size()]); } }