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

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

Snap for 12007880 from 98e260a9 to 24Q4-release

Change-Id: Ic479f7c0a5b87d19a5fe73d3f747552989d798bb
parents fe8ef6ae 98e260a9
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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 {
+11 −8
Original line number Diff line number Diff line
@@ -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 {
  }

}
+10 −0
Original line number Diff line number Diff line
@@ -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
    }
}
+35 −26
Original line number Diff line number Diff line
@@ -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);
    }
}
+123 −88
Original line number Diff line number Diff line
@@ -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;
        }
    }

    /**
@@ -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,9 +354,11 @@ 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 {
            throws IOException {
        try {
            TypedXmlPullParser parser = Xml.newFastPullParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
            parser.setInput(reader);
@@ -364,15 +373,41 @@ public final class VibrationXmlParser {
            XmlReader.readDocumentEndTag(parser);

            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() {
    }
}
Loading