summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-06-12 16:21:38 -0700
committerDianne Hackborn <hackbod@google.com>2013-06-12 18:08:17 -0700
commitdf1c0bf7744d4abd3e2000fcfec01c119b857c75 (patch)
tree4fce2212a526c32f9ccd8418a0fd4f25f87bba8b
parent9ddd70b92caf12d14f7bc81c660c19ebf950746f (diff)
downloadframeworks_base-df1c0bf7744d4abd3e2000fcfec01c119b857c75.zip
frameworks_base-df1c0bf7744d4abd3e2000fcfec01c119b857c75.tar.gz
frameworks_base-df1c0bf7744d4abd3e2000fcfec01c119b857c75.tar.bz2
Add scheme specific part to IntentFilter.
Change-Id: I063d086cdc742800b8e31ddf2942f2e9230e2785
-rw-r--r--api/current.txt9
-rw-r--r--core/java/android/content/IntentFilter.java188
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java13
-rw-r--r--core/res/res/values/attrs_manifest.xml27
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--services/java/com/android/server/pm/Settings.java21
7 files changed, 249 insertions, 30 deletions
diff --git a/api/current.txt b/api/current.txt
index 520d0fe..d4144a8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -954,6 +954,9 @@ package android {
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
field public static final int src = 16843033; // 0x1010119
+ field public static final int ssp = 16843744; // 0x10103e0
+ field public static final int sspPattern = 16843746; // 0x10103e2
+ field public static final int sspPrefix = 16843745; // 0x10103e1
field public static final int stackFromBottom = 16843005; // 0x10100fd
field public static final int starStyle = 16842882; // 0x1010082
field public static final int startColor = 16843165; // 0x101019d
@@ -6322,6 +6325,7 @@ package android.content {
method public final void addDataAuthority(java.lang.String, java.lang.String);
method public final void addDataPath(java.lang.String, int);
method public final void addDataScheme(java.lang.String);
+ method public final void addDataSchemeSpecificPart(java.lang.String, int);
method public final void addDataType(java.lang.String) throws android.content.IntentFilter.MalformedMimeTypeException;
method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
method public final java.util.Iterator<java.lang.String> categoriesIterator();
@@ -6329,6 +6333,7 @@ package android.content {
method public final int countCategories();
method public final int countDataAuthorities();
method public final int countDataPaths();
+ method public final int countDataSchemeSpecificParts();
method public final int countDataSchemes();
method public final int countDataTypes();
method public static android.content.IntentFilter create(java.lang.String, java.lang.String);
@@ -6339,6 +6344,7 @@ package android.content {
method public final android.content.IntentFilter.AuthorityEntry getDataAuthority(int);
method public final android.os.PatternMatcher getDataPath(int);
method public final java.lang.String getDataScheme(int);
+ method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
method public final java.lang.String getDataType(int);
method public final int getPriority();
method public final boolean hasAction(java.lang.String);
@@ -6346,6 +6352,7 @@ package android.content {
method public final boolean hasDataAuthority(android.net.Uri);
method public final boolean hasDataPath(java.lang.String);
method public final boolean hasDataScheme(java.lang.String);
+ method public final boolean hasDataSchemeSpecificPart(java.lang.String);
method public final boolean hasDataType(java.lang.String);
method public final int match(android.content.ContentResolver, android.content.Intent, boolean, java.lang.String);
method public final int match(java.lang.String, java.lang.String, java.lang.String, android.net.Uri, java.util.Set<java.lang.String>, java.lang.String);
@@ -6355,6 +6362,7 @@ package android.content {
method public final int matchDataAuthority(android.net.Uri);
method public final java.util.Iterator<android.os.PatternMatcher> pathsIterator();
method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public final java.util.Iterator<android.os.PatternMatcher> schemeSpecificPartsIterator();
method public final java.util.Iterator<java.lang.String> schemesIterator();
method public final void setPriority(int);
method public final java.util.Iterator<java.lang.String> typesIterator();
@@ -6369,6 +6377,7 @@ package android.content {
field public static final int MATCH_CATEGORY_PATH = 5242880; // 0x500000
field public static final int MATCH_CATEGORY_PORT = 4194304; // 0x400000
field public static final int MATCH_CATEGORY_SCHEME = 2097152; // 0x200000
+ field public static final int MATCH_CATEGORY_SCHEME_SPECIFIC_PART = 5767168; // 0x580000
field public static final int MATCH_CATEGORY_TYPE = 6291456; // 0x600000
field public static final int NO_MATCH_ACTION = -3; // 0xfffffffd
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 5e65b59..4bdbf86 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -50,8 +50,8 @@ import java.util.Set;
* <em>action</em>, <em>data</em>, and <em>categories</em>. For each of these
* characteristics you can provide
* multiple possible matching values (via {@link #addAction},
- * {@link #addDataType}, {@link #addDataScheme} {@link #addDataAuthority},
- * {@link #addDataPath}, and {@link #addCategory}, respectively).
+ * {@link #addDataType}, {@link #addDataScheme}, {@link #addDataSchemeSpecificPart},
+ * {@link #addDataAuthority}, {@link #addDataPath}, and {@link #addCategory}, respectively).
* For actions, the field
* will not be tested if no values have been given (treating it as a wildcard);
* if no data characteristics are specified, however, then the filter will
@@ -106,8 +106,15 @@ import java.util.Set;
* formal RFC schemes!</em> You should thus always use lower case letters
* for your schemes.
*
+ * <p><strong>Data Scheme Specific Part</strong> matches if any of the given values match
+ * the Intent's data scheme specific part <em>and</em> one of the data schemes in the filter
+ * has matched the Intent, <em>or</em> no scheme specific parts were supplied in the filter.
+ * The Intent scheme specific part is determined by calling
+ * {@link Intent#getData} and {@link android.net.Uri#getSchemeSpecificPart} on that URI.
+ * <em>Note that scheme specific part matching is <b>case sensitive</b>.</em>
+ *
* <p><strong>Data Authority</strong> matches if any of the given values match
- * the Intent's data authority <em>and</em> one of the data scheme's in the filter
+ * the Intent's data authority <em>and</em> one of the data schemes in the filter
* has matched the Intent, <em>or</em> no authories were supplied in the filter.
* The Intent authority is determined by calling
* {@link Intent#getData} and {@link android.net.Uri#getAuthority} on that URI.
@@ -135,6 +142,7 @@ public class IntentFilter implements Parcelable {
private static final String PORT_STR = "port";
private static final String HOST_STR = "host";
private static final String AUTH_STR = "auth";
+ private static final String SSP_STR = "ssp";
private static final String SCHEME_STR = "scheme";
private static final String TYPE_STR = "type";
private static final String CAT_STR = "cat";
@@ -164,8 +172,8 @@ public class IntentFilter implements Parcelable {
/**
* The part of a match constant that describes the category of match
* that occurred. May be either {@link #MATCH_CATEGORY_EMPTY},
- * {@link #MATCH_CATEGORY_SCHEME}, {@link #MATCH_CATEGORY_HOST},
- * {@link #MATCH_CATEGORY_PORT},
+ * {@link #MATCH_CATEGORY_SCHEME}, {@link #MATCH_CATEGORY_SCHEME_SPECIFIC_PART},
+ * {@link #MATCH_CATEGORY_HOST}, {@link #MATCH_CATEGORY_PORT},
* {@link #MATCH_CATEGORY_PATH}, or {@link #MATCH_CATEGORY_TYPE}. Higher
* values indicate a better match.
*/
@@ -210,6 +218,11 @@ public class IntentFilter implements Parcelable {
*/
public static final int MATCH_CATEGORY_PATH = 0x0500000;
/**
+ * The filter matched an intent with the same data URI scheme and
+ * scheme specific part.
+ */
+ public static final int MATCH_CATEGORY_SCHEME_SPECIFIC_PART = 0x0580000;
+ /**
* The filter matched an intent with the same data MIME type.
*/
public static final int MATCH_CATEGORY_TYPE = 0x0600000;
@@ -236,6 +249,7 @@ public class IntentFilter implements Parcelable {
private final ArrayList<String> mActions;
private ArrayList<String> mCategories = null;
private ArrayList<String> mDataSchemes = null;
+ private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
private ArrayList<AuthorityEntry> mDataAuthorities = null;
private ArrayList<PatternMatcher> mDataPaths = null;
private ArrayList<String> mDataTypes = null;
@@ -395,6 +409,9 @@ public class IntentFilter implements Parcelable {
if (o.mDataSchemes != null) {
mDataSchemes = new ArrayList<String>(o.mDataSchemes);
}
+ if (o.mDataSchemeSpecificParts != null) {
+ mDataSchemeSpecificParts = new ArrayList<PatternMatcher>(o.mDataSchemeSpecificParts);
+ }
if (o.mDataAuthorities != null) {
mDataAuthorities = new ArrayList<AuthorityEntry>(o.mDataAuthorities);
}
@@ -699,6 +716,77 @@ public class IntentFilter implements Parcelable {
};
/**
+ * Add a new Intent data "scheme specific part" to match against. The filter must
+ * include one or more schemes (via {@link #addDataScheme}) for the
+ * scheme specific part to be considered. If any scheme specific parts are
+ * included in the filter, then an Intent's data must match one of
+ * them. If no scheme specific parts are included, then only the scheme must match.
+ *
+ * @param ssp Either a raw string that must exactly match the scheme specific part
+ * path, or a simple pattern, depending on <var>type</var>.
+ * @param type Determines how <var>ssp</var> will be compared to
+ * determine a match: either {@link PatternMatcher#PATTERN_LITERAL},
+ * {@link PatternMatcher#PATTERN_PREFIX}, or
+ * {@link PatternMatcher#PATTERN_SIMPLE_GLOB}.
+ *
+ * @see #matchData
+ * @see #addDataScheme
+ */
+ public final void addDataSchemeSpecificPart(String ssp, int type) {
+ if (mDataSchemeSpecificParts == null) mDataSchemeSpecificParts =
+ new ArrayList<PatternMatcher>();
+ mDataSchemeSpecificParts.add(new PatternMatcher(ssp, type));
+ }
+
+ /**
+ * Return the number of data scheme specific parts in the filter.
+ */
+ public final int countDataSchemeSpecificParts() {
+ return mDataSchemeSpecificParts != null ? mDataSchemeSpecificParts.size() : 0;
+ }
+
+ /**
+ * Return a data scheme specific part in the filter.
+ */
+ public final PatternMatcher getDataSchemeSpecificPart(int index) {
+ return mDataSchemeSpecificParts.get(index);
+ }
+
+ /**
+ * Is the given data scheme specific part included in the filter? Note that if the
+ * filter does not include any scheme specific parts, false will <em>always</em> be
+ * returned.
+ *
+ * @param data The scheme specific part that is being looked for.
+ *
+ * @return Returns true if the data string matches a scheme specific part listed in the
+ * filter.
+ */
+ public final boolean hasDataSchemeSpecificPart(String data) {
+ if (mDataSchemeSpecificParts == null) {
+ return false;
+ }
+ final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
+ if (numDataSchemeSpecificParts <= 0) {
+ return false;
+ }
+ for (int i = 0; i < numDataSchemeSpecificParts; i++) {
+ final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
+ if (pe.match(data)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return an iterator over the filter's data scheme specific parts.
+ */
+ public final Iterator<PatternMatcher> schemeSpecificPartsIterator() {
+ return mDataSchemeSpecificParts != null ? mDataSchemeSpecificParts.iterator() : null;
+ }
+
+ /**
* Add a new Intent data authority to match against. The filter must
* include one or more schemes (via {@link #addDataScheme}) for the
* authority to be considered. If any authorities are
@@ -900,8 +988,6 @@ public class IntentFilter implements Parcelable {
public final int matchData(String type, String scheme, Uri data) {
final ArrayList<String> types = mDataTypes;
final ArrayList<String> schemes = mDataSchemes;
- final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
- final ArrayList<PatternMatcher> paths = mDataPaths;
int match = MATCH_CATEGORY_EMPTY;
@@ -917,20 +1003,34 @@ public class IntentFilter implements Parcelable {
return NO_MATCH_DATA;
}
- if (authorities != null) {
- int authMatch = matchDataAuthority(data);
- if (authMatch >= 0) {
- if (paths == null) {
- match = authMatch;
- } else if (hasDataPath(data.getPath())) {
- match = MATCH_CATEGORY_PATH;
+ final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
+ if (schemeSpecificParts != null) {
+ match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
+ ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
+ }
+ if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
+ // If there isn't any matching ssp, we need to match an authority.
+ final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
+ if (authorities != null) {
+ int authMatch = matchDataAuthority(data);
+ if (authMatch >= 0) {
+ final ArrayList<PatternMatcher> paths = mDataPaths;
+ if (paths == null) {
+ match = authMatch;
+ } else if (hasDataPath(data.getPath())) {
+ match = MATCH_CATEGORY_PATH;
+ } else {
+ return NO_MATCH_DATA;
+ }
} else {
return NO_MATCH_DATA;
}
- } else {
- return NO_MATCH_DATA;
}
}
+ // If neither an ssp nor an authority matched, we're done.
+ if (match == NO_MATCH_DATA) {
+ return NO_MATCH_DATA;
+ }
} else {
// Special case: match either an Intent with no data URI,
// or with a scheme: URI. This is to give a convenience for
@@ -1173,6 +1273,23 @@ public class IntentFilter implements Parcelable {
serializer.attribute(null, NAME_STR, mDataSchemes.get(i));
serializer.endTag(null, SCHEME_STR);
}
+ N = countDataSchemeSpecificParts();
+ for (int i=0; i<N; i++) {
+ serializer.startTag(null, SSP_STR);
+ PatternMatcher pe = mDataSchemeSpecificParts.get(i);
+ switch (pe.getType()) {
+ case PatternMatcher.PATTERN_LITERAL:
+ serializer.attribute(null, LITERAL_STR, pe.getPath());
+ break;
+ case PatternMatcher.PATTERN_PREFIX:
+ serializer.attribute(null, PREFIX_STR, pe.getPath());
+ break;
+ case PatternMatcher.PATTERN_SIMPLE_GLOB:
+ serializer.attribute(null, SGLOB_STR, pe.getPath());
+ break;
+ }
+ serializer.endTag(null, SSP_STR);
+ }
N = countDataAuthorities();
for (int i=0; i<N; i++) {
serializer.startTag(null, AUTH_STR);
@@ -1238,6 +1355,15 @@ public class IntentFilter implements Parcelable {
if (name != null) {
addDataScheme(name);
}
+ } else if (tagName.equals(SSP_STR)) {
+ String ssp = parser.getAttributeValue(null, LITERAL_STR);
+ if (ssp != null) {
+ addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_LITERAL);
+ } else if ((ssp=parser.getAttributeValue(null, PREFIX_STR)) != null) {
+ addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_PREFIX);
+ } else if ((ssp=parser.getAttributeValue(null, SGLOB_STR)) != null) {
+ addDataSchemeSpecificPart(ssp, PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
} else if (tagName.equals(AUTH_STR)) {
String host = parser.getAttributeValue(null, HOST_STR);
String port = parser.getAttributeValue(null, PORT_STR);
@@ -1289,6 +1415,16 @@ public class IntentFilter implements Parcelable {
du.println(sb.toString());
}
}
+ if (mDataSchemeSpecificParts != null) {
+ Iterator<PatternMatcher> it = mDataSchemeSpecificParts.iterator();
+ while (it.hasNext()) {
+ PatternMatcher pe = it.next();
+ sb.setLength(0);
+ sb.append(prefix); sb.append("Ssp: \"");
+ sb.append(pe); sb.append("\"");
+ du.println(sb.toString());
+ }
+ }
if (mDataAuthorities != null) {
Iterator<AuthorityEntry> it = mDataAuthorities.iterator();
while (it.hasNext()) {
@@ -1363,6 +1499,15 @@ public class IntentFilter implements Parcelable {
} else {
dest.writeInt(0);
}
+ if (mDataSchemeSpecificParts != null) {
+ final int N = mDataSchemeSpecificParts.size();
+ dest.writeInt(N);
+ for (int i=0; i<N; i++) {
+ mDataSchemeSpecificParts.get(i).writeToParcel(dest, 0);
+ }
+ } else {
+ dest.writeInt(0);
+ }
if (mDataAuthorities != null) {
final int N = mDataAuthorities.size();
dest.writeInt(N);
@@ -1428,14 +1573,21 @@ public class IntentFilter implements Parcelable {
}
int N = source.readInt();
if (N > 0) {
- mDataAuthorities = new ArrayList<AuthorityEntry>();
+ mDataSchemeSpecificParts = new ArrayList<PatternMatcher>(N);
+ for (int i=0; i<N; i++) {
+ mDataSchemeSpecificParts.add(new PatternMatcher(source));
+ }
+ }
+ N = source.readInt();
+ if (N > 0) {
+ mDataAuthorities = new ArrayList<AuthorityEntry>(N);
for (int i=0; i<N; i++) {
mDataAuthorities.add(new AuthorityEntry(source));
}
}
N = source.readInt();
if (N > 0) {
- mDataPaths = new ArrayList<PatternMatcher>();
+ mDataPaths = new ArrayList<PatternMatcher>(N);
for (int i=0; i<N; i++) {
mDataPaths.add(new PatternMatcher(source));
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1b997f0..a3bcfcb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3288,6 +3288,24 @@ public class PackageParser {
outInfo.addDataScheme(str);
}
+ str = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
+ if (str != null) {
+ outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
+ }
+
+ str = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
+ if (str != null) {
+ outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
+ }
+
+ str = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
+ if (str != null) {
+ outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+
String host = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_host, 0);
String port = sa.getNonConfigurationString(
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a674776..aa94728 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -327,6 +327,17 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
// Look through the resolved filter to determine which part
// of it matched the original Intent.
+ Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
+ if (pIt != null) {
+ String ssp = data.getSchemeSpecificPart();
+ while (ssp != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(ssp)) {
+ filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
+ break;
+ }
+ }
+ }
Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
if (aIt != null) {
while (aIt.hasNext()) {
@@ -339,7 +350,7 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
}
}
}
- Iterator<PatternMatcher> pIt = ri.filter.pathsIterator();
+ pIt = ri.filter.pathsIterator();
if (pIt != null) {
String path = data.getPath();
while (path != null && pIt.hasNext()) {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0aaa5b7..728b1b0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1624,6 +1624,27 @@
case-sensitive, unlike the formal RFC. As a result,
schemes here should always use lower case letters.</em></p> -->
<attr name="scheme" format="string" />
+ <!-- Specify a URI scheme specific part that must exactly match, as per
+ {@link android.content.IntentFilter#addDataSchemeSpecificPart
+ IntentFilter.addDataSchemeSpecificPart()} with
+ {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+ <attr name="ssp" format="string" />
+ <!-- Specify a URI scheme specific part that must be a prefix to match, as per
+ {@link android.content.IntentFilter#addDataSchemeSpecificPart
+ IntentFilter.addDataSchemeSpecificPart()} with
+ {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+ <attr name="sspPrefix" format="string" />
+ <!-- Specify a URI scheme specific part that matches a simple pattern, as per
+ {@link android.content.IntentFilter#addDataSchemeSpecificPart
+ IntentFilter.addDataSchemeSpecificPart()} with
+ {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+ Note that because '\' is used as an escape character when
+ reading the string from XML (before it is parsed as a pattern),
+ you will need to double-escape: for example a literal "*" would
+ be written as "\\*" and a literal "\" would be written as
+ "\\\\". This is basically the same as what you would need to
+ write if constructing the string in Java code. -->
+ <attr name="sspPattern" format="string" />
<!-- Specify a URI authority host that is handled, as per
{@link android.content.IntentFilter#addDataAuthority
IntentFilter.addDataAuthority()}.
@@ -1638,17 +1659,17 @@
<attr name="port" format="string" />
<!-- Specify a URI path that must exactly match, as per
{@link android.content.IntentFilter#addDataPath
- IntentFilter.addDataAuthority()} with
+ IntentFilter.addDataPath()} with
{@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
<attr name="path" />
<!-- Specify a URI path that must be a prefix to match, as per
{@link android.content.IntentFilter#addDataPath
- IntentFilter.addDataAuthority()} with
+ IntentFilter.addDataPath()} with
{@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
<attr name="pathPrefix" />
<!-- Specify a URI path that matches a simple pattern, as per
{@link android.content.IntentFilter#addDataPath
- IntentFilter.addDataAuthority()} with
+ IntentFilter.addDataPath()} with
{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
Note that because '\' is used as an escape character when
reading the string from XML (before it is parsed as a pattern),
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 36a7a86..3858dcf 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2063,5 +2063,8 @@
<public type="attr" name="fromScene" />
<public type="attr" name="toScene" />
<public type="attr" name="transition" />
+ <public type="attr" name="ssp" />
+ <public type="attr" name="sspPrefix" />
+ <public type="attr" name="sspPattern" />
</resources>
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b7810ba..495e97d 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1917,15 +1917,20 @@ final class Settings {
if (tmpPa.countDataSchemes() > 0) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(tmpPa.getDataScheme(0));
- if (tmpPa.countDataAuthorities() > 0) {
- IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
- if (auth.getHost() != null) {
- builder.authority(auth.getHost());
+ if (tmpPa.countDataSchemeSpecificParts() > 0) {
+ PatternMatcher path = tmpPa.getDataSchemeSpecificPart(0);
+ builder.opaquePart(path.getPath());
+ } else {
+ if (tmpPa.countDataAuthorities() > 0) {
+ IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
+ if (auth.getHost() != null) {
+ builder.authority(auth.getHost());
+ }
+ }
+ if (tmpPa.countDataPaths() > 0) {
+ PatternMatcher path = tmpPa.getDataPath(0);
+ builder.path(path.getPath());
}
- }
- if (tmpPa.countDataPaths() > 0) {
- PatternMatcher path = tmpPa.getDataPath(0);
- builder.path(path.getPath());
}
intent.setData(builder.build());
} else if (tmpPa.countDataTypes() > 0) {