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

Commit d3145843 authored by William Loh's avatar William Loh
Browse files

Add <uri-relative-filter-group> to intent filters.

Introduce new <uri-relative-filter-group> tag to define a new matching
rule where all matchers in the group must match. Each rule group will be
evaluated in the order they are defined in the manifest. These rules
will only be evaluated if no matches found in mDataPaths.

Each URI relative filter group can define matchers for URI fragments and
queries in addtion to paths.

Bug: 307556883
Test: atest CtsContentTestCases:IntentFilterTest
Test: atest PackageParserTest
Change-Id: Ida1c7a1440b99fd5af2913e5c10c6886c511256f
parent c96387d3
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -442,6 +442,7 @@ package android {
    field public static final int alertDialogTheme = 16843529; // 0x1010309
    field public static final int alignmentMode = 16843642; // 0x101037a
    field public static final int allContactsName = 16843468; // 0x10102cc
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int allow;
    field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
    field public static final int allowBackup = 16843392; // 0x1010280
    field public static final int allowClearUserData = 16842757; // 0x1010005
@@ -845,6 +846,7 @@ package android {
    field public static final int format24Hour = 16843723; // 0x10103cb
    field public static final int fraction = 16843992; // 0x10104d8
    field public static final int fragment = 16843491; // 0x10102e3
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentAdvancedPattern;
    field public static final int fragmentAllowEnterTransitionOverlap = 16843976; // 0x10104c8
    field public static final int fragmentAllowReturnTransitionOverlap = 16843977; // 0x10104c9
    field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
@@ -855,10 +857,13 @@ package android {
    field public static final int fragmentFadeExitAnimation = 16843498; // 0x10102ea
    field public static final int fragmentOpenEnterAnimation = 16843493; // 0x10102e5
    field public static final int fragmentOpenExitAnimation = 16843494; // 0x10102e6
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPattern;
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPrefix;
    field public static final int fragmentReenterTransition = 16843975; // 0x10104c7
    field public static final int fragmentReturnTransition = 16843973; // 0x10104c5
    field public static final int fragmentSharedElementEnterTransition = 16843972; // 0x10104c4
    field public static final int fragmentSharedElementReturnTransition = 16843974; // 0x10104c6
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentSuffix;
    field public static final int freezesText = 16843116; // 0x101016c
    field public static final int fromAlpha = 16843210; // 0x10101ca
    field public static final int fromDegrees = 16843187; // 0x10101b3
@@ -1327,10 +1332,15 @@ package android {
    field public static final int propertyYName = 16843893; // 0x1010475
    field public static final int protectionLevel = 16842761; // 0x1010009
    field public static final int publicKey = 16843686; // 0x10103a6
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int query;
    field public static final int queryActionMsg = 16843227; // 0x10101db
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryAdvancedPattern;
    field public static final int queryAfterZeroResults = 16843394; // 0x1010282
    field public static final int queryBackground = 16843911; // 0x1010487
    field public static final int queryHint = 16843608; // 0x1010358
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPattern;
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPrefix;
    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int querySuffix;
    field public static final int quickContactBadgeStyleSmallWindowLarge = 16843443; // 0x10102b3
    field public static final int quickContactBadgeStyleSmallWindowMedium = 16843442; // 0x10102b2
    field public static final int quickContactBadgeStyleSmallWindowSmall = 16843441; // 0x10102b1
@@ -11385,10 +11395,12 @@ package android.content {
    method public final void addDataScheme(String);
    method public final void addDataSchemeSpecificPart(String, int);
    method public final void addDataType(String) throws android.content.IntentFilter.MalformedMimeTypeException;
    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void addUriRelativeFilterGroup(@NonNull android.content.UriRelativeFilterGroup);
    method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicate();
    method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicateWithTypeResolution(@NonNull android.content.ContentResolver);
    method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
    method public final java.util.Iterator<java.lang.String> categoriesIterator();
    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void clearUriRelativeFilterGroups();
    method public final int countActions();
    method public final int countCategories();
    method public final int countDataAuthorities();
@@ -11396,6 +11408,7 @@ package android.content {
    method public final int countDataSchemeSpecificParts();
    method public final int countDataSchemes();
    method public final int countDataTypes();
    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final int countUriRelativeFilterGroups();
    method public static android.content.IntentFilter create(String, String);
    method public final int describeContents();
    method public void dump(android.util.Printer, String);
@@ -11407,6 +11420,7 @@ package android.content {
    method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
    method public final String getDataType(int);
    method public final int getPriority();
    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") @NonNull public final android.content.UriRelativeFilterGroup getUriRelativeFilterGroup(int);
    method public final boolean hasAction(String);
    method public final boolean hasCategory(String);
    method public final boolean hasDataAuthority(android.net.Uri);
@@ -11828,6 +11842,27 @@ package android.content {
    field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
  }
  @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilter {
    ctor public UriRelativeFilter(int, int, @NonNull String);
    method @NonNull public String getFilter();
    method public int getPatternType();
    method public int getUriPart();
    method public boolean matchData(@NonNull android.net.Uri);
    field public static final int FRAGMENT = 2; // 0x2
    field public static final int PATH = 0; // 0x0
    field public static final int QUERY = 1; // 0x1
  }
  @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilterGroup {
    ctor public UriRelativeFilterGroup(int);
    method public void addUriRelativeFilter(@NonNull android.content.UriRelativeFilter);
    method public int getAction();
    method @NonNull public java.util.Collection<android.content.UriRelativeFilter> getUriRelativeFilters();
    method public boolean matchData(@NonNull android.net.Uri);
    field public static final int ACTION_ALLOW = 0; // 0x0
    field public static final int ACTION_BLOCK = 1; // 0x1
  }
}
package android.content.om {
+135 −5
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

package android.content;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.Flags;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -175,6 +177,7 @@ public class IntentFilter implements Parcelable {
    private static final String ACTION_STR = "action";
    private static final String AUTO_VERIFY_STR = "autoVerify";
    private static final String EXTRAS_STR = "extras";
    private static final String URI_RELATIVE_FILTER_GROUP_STR = "uriRelativeFilterGroup";

    private static final int[] EMPTY_INT_ARRAY = new int[0];
    private static final long[] EMPTY_LONG_ARRAY = new long[0];
@@ -324,6 +327,7 @@ public class IntentFilter implements Parcelable {
    private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
    private ArrayList<AuthorityEntry> mDataAuthorities = null;
    private ArrayList<PatternMatcher> mDataPaths = null;
    private ArrayList<UriRelativeFilterGroup> mUriRelativeFilterGroups = null;
    private ArrayList<String> mStaticDataTypes = null;
    private ArrayList<String> mDataTypes = null;
    private ArrayList<String> mMimeGroups = null;
@@ -520,6 +524,10 @@ public class IntentFilter implements Parcelable {
        if (o.mDataPaths != null) {
            mDataPaths = new ArrayList<PatternMatcher>(o.mDataPaths);
        }
        if (o.mUriRelativeFilterGroups != null) {
            mUriRelativeFilterGroups =
                    new ArrayList<UriRelativeFilterGroup>(o.mUriRelativeFilterGroups);
        }
        if (o.mMimeGroups != null) {
            mMimeGroups = new ArrayList<String>(o.mMimeGroups);
        }
@@ -1562,6 +1570,63 @@ public class IntentFilter implements Parcelable {
        return mDataPaths != null ? mDataPaths.iterator() : null;
    }

    /**
     * Add a new URI relative filter group to match against the Intent data.  The
     * intent filter must include one or more schemes (via {@link #addDataScheme})
     * <em>and</em> one or more authorities (via {@link #addDataAuthority}) for
     * the group to be considered.
     *
     * <p>Groups will be matched in the order they were added and matching will only
     * be done if no data paths match or if none are included. If both data paths and
     * groups are not included, then only the scheme/authority must match.</p>
     *
     * @param group A {@link UriRelativeFilterGroup} to match the URI.
     *
     * @see UriRelativeFilterGroup
     * @see #matchData
     * @see #addDataScheme
     * @see #addDataAuthority
     */
    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
    public final void addUriRelativeFilterGroup(@NonNull UriRelativeFilterGroup group) {
        Objects.requireNonNull(group);
        if (mUriRelativeFilterGroups == null) {
            mUriRelativeFilterGroups = new ArrayList<>();
        }
        mUriRelativeFilterGroups.add(group);
    }

    /**
     * Return the number of URI relative filter groups in the intent filter.
     */
    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
    public final int countUriRelativeFilterGroups() {
        return mUriRelativeFilterGroups == null ? 0 : mUriRelativeFilterGroups.size();
    }

    /**
     * Return a URI relative filter group in the intent filter.
     *
     * <p>Note: use of this method will result in a NullPointerException
     * if no groups exists for this intent filter.</p>
     *
     * @param index index of the element to return
     * @throws IndexOutOfBoundsException if index is out of range
     */
    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
    @NonNull
    public final UriRelativeFilterGroup getUriRelativeFilterGroup(int index) {
        return mUriRelativeFilterGroups.get(index);
    }

    /**
     * Removes all existing URI relative filter groups in the intent filter.
     */
    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
    public final void clearUriRelativeFilterGroups() {
        mUriRelativeFilterGroups = null;
    }

    /**
     * Match this intent filter against the given Intent data.  This ignores
     * the data scheme -- unlike {@link #matchData}, the authority will match
@@ -1677,6 +1742,17 @@ public class IntentFilter implements Parcelable {
                    int authMatch = matchDataAuthority(data, wildcardSupported);
                    if (authMatch >= 0) {
                        final ArrayList<PatternMatcher> paths = mDataPaths;
                        final ArrayList<UriRelativeFilterGroup> groups = mUriRelativeFilterGroups;
                        if (Flags.relativeReferenceIntentFilters()) {
                            if (paths == null && groups == null) {
                                match = authMatch;
                            } else if (hasDataPath(data.getPath(), wildcardSupported)
                                    || matchRelRefGroups(data)) {
                                match = MATCH_CATEGORY_PATH;
                            } else {
                                return NO_MATCH_DATA;
                            }
                        } else {
                            if (paths == null) {
                                match = authMatch;
                            } else if (hasDataPath(data.getPath(), wildcardSupported)) {
@@ -1684,6 +1760,7 @@ public class IntentFilter implements Parcelable {
                            } else {
                                return NO_MATCH_DATA;
                            }
                        }
                    } else {
                        return NO_MATCH_DATA;
                    }
@@ -1726,6 +1803,19 @@ public class IntentFilter implements Parcelable {
        return match + MATCH_ADJUSTMENT_NORMAL;
    }

    private boolean matchRelRefGroups(Uri data) {
        if (mUriRelativeFilterGroups == null) {
            return false;
        }
        for (int i = 0; i < mUriRelativeFilterGroups.size(); i++) {
            UriRelativeFilterGroup group = mUriRelativeFilterGroups.get(i);
            if (group.matchData(data)) {
                return group.getAction() == UriRelativeFilterGroup.ACTION_ALLOW;
            }
        }
        return false;
    }

    /**
     * Add a new Intent category to match against.  The semantics of
     * categories is the opposite of actions -- an Intent includes the
@@ -2486,6 +2576,12 @@ public class IntentFilter implements Parcelable {
            }
            serializer.endTag(null, EXTRAS_STR);
        }
        if (Flags.relativeReferenceIntentFilters()) {
            N = countUriRelativeFilterGroups();
            for (int i = 0; i < N; i++) {
                mUriRelativeFilterGroups.get(i).writeToXml(serializer);
            }
        }
    }

    /**
@@ -2614,6 +2710,9 @@ public class IntentFilter implements Parcelable {
                }
            } else if (tagName.equals(EXTRAS_STR)) {
                mExtras = PersistableBundle.restoreFromXml(parser);
            } else if (Flags.relativeReferenceIntentFilters()
                    && URI_RELATIVE_FILTER_GROUP_STR.equals(tagName)) {
                addUriRelativeFilterGroup(new UriRelativeFilterGroup(parser));
            } else {
                Log.w("IntentFilter", "Unknown tag parsing IntentFilter: " + tagName);
            }
@@ -2680,6 +2779,12 @@ public class IntentFilter implements Parcelable {
        if (mExtras != null) {
            mExtras.dumpDebug(proto, IntentFilterProto.EXTRAS);
        }
        if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
            Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
            while (it.hasNext()) {
                it.next().dumpDebug(proto, IntentFilterProto.URI_RELATIVE_FILTER_GROUPS);
            }
        }
        proto.end(token);
    }

@@ -2744,6 +2849,15 @@ public class IntentFilter implements Parcelable {
                du.println(sb.toString());
            }
        }
        if (mUriRelativeFilterGroups != null) {
            Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
            while (it.hasNext()) {
                sb.setLength(0);
                sb.append(prefix); sb.append("UriRelativeFilterGroup: \"");
                sb.append(it.next()); sb.append("\"");
                du.println(sb.toString());
            }
        }
        if (mStaticDataTypes != null) {
            Iterator<String> it = mStaticDataTypes.iterator();
            while (it.hasNext()) {
@@ -2883,6 +2997,15 @@ public class IntentFilter implements Parcelable {
        } else {
            dest.writeInt(0);
        }
        if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
            final int N = mUriRelativeFilterGroups.size();
            dest.writeInt(N);
            for (int i = 0; i < N; i++) {
                mUriRelativeFilterGroups.get(i).writeToParcel(dest, flags);
            }
        } else {
            dest.writeInt(0);
        }
    }

    /**
@@ -2989,6 +3112,13 @@ public class IntentFilter implements Parcelable {
        if (source.readInt() != 0) {
            mExtras = PersistableBundle.CREATOR.createFromParcel(source);
        }
        N = source.readInt();
        if (Flags.relativeReferenceIntentFilters() && N > 0) {
            mUriRelativeFilterGroups = new ArrayList<UriRelativeFilterGroup>(N);
            for (int i = 0; i < N; i++) {
                mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source));
            }
        }
    }

    private boolean hasPartialTypes() {
+260 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.Flags;
import android.net.Uri;
import android.os.Parcel;
import android.os.PatternMatcher;
import android.util.proto.ProtoOutputStream;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * A filter for matching Intent URI Data as part of a
 * {@link UriRelativeFilterGroup}. A single filter can only be
 * matched against either a URI path, query or fragment
 */
@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
public final class UriRelativeFilter {
    private static final String FILTER_STR = "filter";
    private static final String PART_STR = "part";
    private static final String PATTERN_STR = "pattern";
    static final String URI_RELATIVE_FILTER_STR = "uriRelativeFilter";

    /**
     * Value to indicate that the filter is to be applied to a URI path.
     */
    public static final int PATH = 0;
    /**
     * Value to indicate that the filter is to be applied to a URI query.
     */
    public static final int QUERY = 1;
    /**
     * Value to indicate that the filter is to be applied to a URI fragment.
     */
    public static final int FRAGMENT = 2;

    /** @hide */
    @IntDef(value = {
            PATH,
            QUERY,
            FRAGMENT
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface UriPart {}

    private final @UriPart int mUriPart;
    private final @PatternMatcher.PatternType int mPatternType;
    private final String mFilter;

    /**
     * Creates a new UriRelativeFilter.
     *
     * @param uriPart The URI part this filter operates on. Can be either a
     *                {@link UriRelativeFilter#PATH}, {@link UriRelativeFilter#QUERY},
     *                or {@link UriRelativeFilter#FRAGMENT}.
     * @param patternType The pattern type of the filter. Can be either a
     *                    {@link PatternMatcher#PATTERN_LITERAL},
     *                    {@link PatternMatcher#PATTERN_PREFIX},
*                         {@link PatternMatcher#PATTERN_SUFFIX},
     *                    {@link PatternMatcher#PATTERN_SIMPLE_GLOB},
     *                    or {@link PatternMatcher#PATTERN_ADVANCED_GLOB}.
     * @param filter A literal or pattern string depedning on patterType
     *               used to match a uriPart .
     */
    public UriRelativeFilter(
            @UriPart int uriPart,
            @PatternMatcher.PatternType int patternType,
            @NonNull String filter) {
        mUriPart = uriPart;
        com.android.internal.util.AnnotationValidations.validate(
                UriPart.class, null, mUriPart);
        mPatternType = patternType;
        com.android.internal.util.AnnotationValidations.validate(
                PatternMatcher.PatternType.class, null, mPatternType);
        mFilter = filter;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mFilter);
    }

    /**
     * The URI part this filter operates on.
     */
    public @UriPart int getUriPart() {
        return mUriPart;
    }

    /**
     * The pattern type of the filter.
     */
    public @PatternMatcher.PatternType int getPatternType() {
        return mPatternType;
    }

    /**
     * The string used to filter the URI.
     */
    public @NonNull String getFilter() {
        return mFilter;
    }

    /**
     * Match this URI filter against an Intent's data. QUERY filters can
     * match against any key value pair in the query string. PATH and
     * FRAGMENT filters must match the entire string.
     *
     * @param data The full data string to match against, as supplied in
     *             Intent.data.
     *
     * @return true if there is a match.
     */
    public boolean matchData(@NonNull Uri data) {
        PatternMatcher pe = new PatternMatcher(mFilter, mPatternType);
        switch (getUriPart()) {
            case PATH:
                return pe.match(data.getPath());
            case QUERY:
                return matchQuery(pe, data.getQuery());
            case FRAGMENT:
                return pe.match(data.getFragment());
            default:
                return false;
        }
    }

    private boolean matchQuery(PatternMatcher pe, String query) {
        if (query != null) {
            String[] params = query.split("&");
            if (params.length == 1) {
                params = query.split(";");
            }
            for (int i = 0; i < params.length; i++) {
                if (pe.match(params[i])) return true;
            }
        }
        return false;
    }

    /** @hide */
    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
        long token = proto.start(fieldId);
        proto.write(UriRelativeFilterProto.URI_PART, mUriPart);
        proto.write(UriRelativeFilterProto.PATTERN_TYPE, mPatternType);
        proto.write(UriRelativeFilterProto.FILTER, mFilter);
        proto.end(token);
    }

    /** @hide */
    public void writeToXml(XmlSerializer serializer) throws IOException {
        serializer.startTag(null, URI_RELATIVE_FILTER_STR);
        serializer.attribute(null, PATTERN_STR, Integer.toString(mPatternType));
        serializer.attribute(null, PART_STR, Integer.toString(mUriPart));
        serializer.attribute(null, FILTER_STR, mFilter);
        serializer.endTag(null, URI_RELATIVE_FILTER_STR);
    }

    private String uriPartToString() {
        switch (mUriPart) {
            case PATH:
                return "PATH";
            case QUERY:
                return "QUERY";
            case FRAGMENT:
                return "FRAGMENT";
            default:
                return "UNKNOWN";
        }
    }

    private String patternTypeToString() {
        switch (mPatternType) {
            case PatternMatcher.PATTERN_LITERAL:
                return "LITERAL";
            case PatternMatcher.PATTERN_PREFIX:
                return "PREFIX";
            case PatternMatcher.PATTERN_SIMPLE_GLOB:
                return "GLOB";
            case PatternMatcher.PATTERN_ADVANCED_GLOB:
                return "ADVANCED_GLOB";
            case PatternMatcher.PATTERN_SUFFIX:
                return "SUFFIX";
            default:
                return "UNKNOWN";
        }
    }

    @Override
    public String toString() {
        return "UriRelativeFilter { "
                + "uriPart = " + uriPartToString() + ", "
                + "patternType = " + patternTypeToString() + ", "
                + "filter = " + mFilter
                + " }";
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        @SuppressWarnings("unchecked")
        UriRelativeFilter that = (UriRelativeFilter) o;
        return mUriPart == that.mUriPart
                && mPatternType == that.mPatternType
                && java.util.Objects.equals(mFilter, that.mFilter);
    }

    @Override
    public int hashCode() {
        int _hash = 1;
        _hash = 31 * _hash + mUriPart;
        _hash = 31 * _hash + mPatternType;
        _hash = 31 * _hash + java.util.Objects.hashCode(mFilter);
        return _hash;
    }

    /** @hide */
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mUriPart);
        dest.writeInt(mPatternType);
        dest.writeString(mFilter);
    }

    /** @hide */
    UriRelativeFilter(@NonNull android.os.Parcel in) {
        mUriPart = in.readInt();
        mPatternType = in.readInt();
        mFilter = in.readString();
    }

    /** @hide */
    public UriRelativeFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
        mUriPart = Integer.parseInt(parser.getAttributeValue(null, PART_STR));
        mPatternType = Integer.parseInt(parser.getAttributeValue(null, PATTERN_STR));
        mFilter = parser.getAttributeValue(null, FILTER_STR);
    }
}
+216 −0

File added.

Preview size limit exceeded, changes collapsed.

+8 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading