Uri.java revision e26450b7142feae9902b432eb01bcd33f3cbd1bd
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.net; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedyimport android.annotation.Nullable; 20fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkeyimport android.content.Intent; 2165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkeyimport android.os.Environment; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 24a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkeyimport android.os.StrictMode; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 26846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 27e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedyimport libcore.net.UriCodec; 28e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 3065c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkeyimport java.io.IOException; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.URLEncoder; 33d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughesimport java.nio.charset.StandardCharsets; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.AbstractList; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Collections; 3758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodsonimport java.util.LinkedHashSet; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 39ccae412deda8b0c165c86f395752c0667a3411a6Nick Pellyimport java.util.Locale; 40846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkeyimport java.util.Objects; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.RandomAccess; 4258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodsonimport java.util.Set; 43846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Immutable URI reference. A URI reference includes a URI and a fragment, the 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * component of the URI following a '#'. Builds and parses URI references 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which conform to 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <a href="http://www.faqs.org/rfcs/rfc2396.html">RFC 2396</a>. 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>In the interest of performance, this class performs little to no 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * validation. Behavior is undefined for invalid input. This class is very 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * forgiving--in the face of invalid input, it will return garbage 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rather than throw an exception unless otherwise specified. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class Uri implements Parcelable, Comparable<Uri> { 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project This class aims to do as little up front work as possible. To accomplish 6058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson that, we vary the implementation depending on what the user passes in. 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project For example, we have one implementation if the user passes in a 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project URI string (StringUri) and another if the user passes in the 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project individual components (OpaqueUri). 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *Concurrency notes*: Like any truly immutable object, this class is safe 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for concurrent use. This class uses a caching pattern in some places where 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project it doesn't use volatile or synchronized. This is safe to do with ints 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project because getting or setting an int is atomic. It's safe to do with a String 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project because the internal fields are final and the memory model guarantees other 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project threads won't see a partially initialized instance. We are not guaranteed 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project that some threads will immediately see changes from other threads on 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project certain platforms, but we don't mind if those threads reconstruct the 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cached result. As a result, we get thread safe caching with no concurrency 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project overhead, which means the most common case, access from a single thread, 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project is as fast as possible. 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project From the Java Language spec.: 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "17.5 Final Field Semantics 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ... when the object is seen by another thread, that thread will always 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project see the correctly constructed version of that object's final fields. 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project It will also see versions of any object or array referenced by 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project those final fields that are at least as up-to-date as the final fields 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project are." 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project In that same vein, all non-transient fields within Uri 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project implementations should be final and immutable so as to ensure true 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project immutability for clients even when they don't use proper concurrency 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project control. 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project For reference, from RFC 2396: 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "4.3. Parsing a URI Reference 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project A URI reference is typically parsed according to the four main 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project components and fragment identifier in order to determine what 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project components are present and whether the reference is relative or 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project absolute. The individual components are then parsed for their 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project subparts and, if not opaque, to verify their validity. 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Although the BNF defines what is allowed in each component, it is 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ambiguous in terms of differentiating between an authority component 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project and a path component that begins with two slash characters. The 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project greedy algorithm is used for disambiguation: the left-most matching 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rule soaks up as much of the URI reference string as it is capable of 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project matching. In other words, the authority component wins." 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project The "four main components" of a hierarchical URI consist of 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project <scheme>://<authority><path>?<query> 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Log tag. */ 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String LOG = Uri.class.getSimpleName(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 118a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * NOTE: EMPTY accesses this field during its own initialization, so this 119a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * field *must* be initialized first, or else EMPTY will see a null value! 120a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * 121a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * Placeholder for strings which haven't been cached. This enables us 122a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * to cache null. We intentionally create a new String instance so we can 123a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * compare its identity and there is no chance we will confuse it with 124a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru * user data. 125a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru */ 126a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru @SuppressWarnings("RedundantStringConstructorCall") 127a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru private static final String NOT_CACHED = new String("NOT CACHED"); 128a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru 129a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru /** 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The empty URI, equivalent to "". 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Uri EMPTY = new HierarchicalUri(null, Part.NULL, 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathPart.EMPTY, Part.NULL, Part.NULL); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prevents external subclassing. 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri() {} 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if this URI is hierarchical like "http://google.com". 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Absolute URIs are hierarchical if the scheme-specific part starts with 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a '/'. Relative URIs are always hierarchical. 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract boolean isHierarchical(); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if this URI is opaque like "mailto:nobody@google.com". The 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scheme-specific part of an opaque URI cannot start with a '/'. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isOpaque() { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !isHierarchical(); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1564465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * Returns true if this URI is relative, i.e. if it doesn't contain an 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * explicit scheme. 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if this URI is relative, false if it's absolute 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract boolean isRelative(); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1644465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * Returns true if this URI is absolute, i.e. if it contains an 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * explicit scheme. 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if this URI is absolute, false if it's relative 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isAbsolute() { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return !isRelative(); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the scheme of this URI. Example: "http" 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the scheme or null if this is a relative URI 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 178e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getScheme(); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1824465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * Gets the scheme-specific part of this URI, i.e. everything between 1834465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * the scheme separator ':' and the fragment separator '#'. If this is a 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * relative URI, this method returns the entire URI. Decodes escaped octets. 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Example: "//www.google.com/search?q=android" 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded scheme-specific-part 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getSchemeSpecificPart(); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1934465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * Gets the scheme-specific part of this URI, i.e. everything between 1944465d1a03ee5fddc5987c19fc36b0bb79e19572fNewton Allen * the scheme separator ':' and the fragment separator '#'. If this is a 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * relative URI, this method returns the entire URI. Leaves escaped octets 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * intact. 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Example: "//www.google.com/search?q=android" 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded scheme-specific-part 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedSchemeSpecificPart(); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded authority part of this URI. For 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * server addresses, the authority is structured as follows: 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@code [ userinfo '@' ] host [ ':' port ]} 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Examples: "google.com", "bob@google.com:80" 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the authority for this URI or null if not present 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 213e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getAuthority(); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded authority part of this URI. For 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * server addresses, the authority is structured as follows: 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@code [ userinfo '@' ] host [ ':' port ]} 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Examples: "google.com", "bob@google.com:80" 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the authority for this URI or null if not present 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 225e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedAuthority(); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded user information from the authority. 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For example, if the authority is "nobody@google.com", this method will 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return "nobody". 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the user info for this URI or null if not present 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 235e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getUserInfo(); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded user information from the authority. 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For example, if the authority is "nobody@google.com", this method will 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * return "nobody". 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the user info for this URI or null if not present 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 245e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedUserInfo(); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded host from the authority for this URI. For example, 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the authority is "bob@google.com", this method will return 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "google.com". 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the host for this URI or null if not present 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 255e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getHost(); 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the port from the authority for this URI. For example, 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the authority is "google.com:80", this method will return 80. 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the port for this URI or -1 if invalid or not present 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getPort(); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded path. 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded path, or null if this is not a hierarchical URI 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (like "mailto:nobody@google.com") or the URI is invalid 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 272e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getPath(); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded path. 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the encoded path, or null if this is not a hierarchical URI 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (like "mailto:nobody@google.com") or the URI is invalid 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 281e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedPath(); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded query component from this URI. The query comes after 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the query separator ('?') and before the fragment separator ('#'). This 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method would return "q=android" for 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "http://www.google.com/search?q=android". 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded query or null if there isn't one 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 292e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getQuery(); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded query component from this URI. The query comes after 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the query separator ('?') and before the fragment separator ('#'). This 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method would return "q=android" for 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "http://www.google.com/search?q=android". 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the encoded query or null if there isn't one 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 303e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedQuery(); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded fragment part of this URI, everything after the '#'. 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded fragment or null if there isn't one 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 311e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getFragment(); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the encoded fragment part of this URI, everything after the '#'. 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the encoded fragment or null if there isn't one 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 319e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getEncodedFragment(); 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded path segments. 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return decoded path segments, each without a leading or trailing '/' 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract List<String> getPathSegments(); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the decoded last segment in the path. 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded last segment or null if the path is empty 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 334e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String getLastPathSegment(); 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compares this Uri to another object for equality. Returns true if the 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * encoded string representations of this Uri and the given Uri are 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * equal. Case counts. Paths are not normalized. If one Uri specifies a 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * default port explicitly and the other leaves it implicit, they will not 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be considered equal. 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean equals(Object o) { 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!(o instanceof Uri)) { 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri other = (Uri) o; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return toString().equals(other.toString()); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Hashes the encoded string represention of this Uri consistently with 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #equals(Object)}. 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int hashCode() { 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return toString().hashCode(); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compares the string representation of this Uri with that of 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * another. 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int compareTo(Uri other) { 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return toString().compareTo(other.toString()); 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the encoded string representation of this URI. 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Example: "http://google.com/" 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract String toString(); 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 37790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn * Return a string representation of the URI that is safe to print 37890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn * to logs and other places where PII should be avoided. 37990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn * @hide 38090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn */ 38190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn public String toSafeString() { 38290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn String scheme = getScheme(); 38390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn String ssp = getSchemeSpecificPart(); 38490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (scheme != null) { 38590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip") 38690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto") 38790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn || scheme.equalsIgnoreCase("mailto")) { 38890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn StringBuilder builder = new StringBuilder(64); 38990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(scheme); 39090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(':'); 39190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (ssp != null) { 39290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn for (int i=0; i<ssp.length(); i++) { 39390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn char c = ssp.charAt(i); 39490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (c == '-' || c == '@' || c == '.') { 39590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(c); 39690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } else { 39790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append('x'); 39890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 39990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 40090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 40190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn return builder.toString(); 4023f24a1d94a42762c245a32272c797250a804cfc3Alex Klyubin } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https") 4033f24a1d94a42762c245a32272c797250a804cfc3Alex Klyubin || scheme.equalsIgnoreCase("ftp")) { 4043f24a1d94a42762c245a32272c797250a804cfc3Alex Klyubin ssp = "//" + ((getHost() != null) ? getHost() : "") 4053f24a1d94a42762c245a32272c797250a804cfc3Alex Klyubin + ((getPort() != -1) ? (":" + getPort()) : "") 4063f24a1d94a42762c245a32272c797250a804cfc3Alex Klyubin + "/..."; 40790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 40890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 40990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn // Not a sensitive scheme, but let's still be conservative about 41090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn // the data we include -- only the ssp, not the query params or 41190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn // fragment, because those can often have sensitive info. 41290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn StringBuilder builder = new StringBuilder(64); 41390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (scheme != null) { 41490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(scheme); 41590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(':'); 41690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 41790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn if (ssp != null) { 41890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn builder.append(ssp); 41990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 42090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn return builder.toString(); 42190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn } 42290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn 42390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn /** 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructs a new builder, copying the attributes from this Uri. 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract Builder buildUpon(); 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Index of a component which was not found. */ 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final static int NOT_FOUND = -1; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Placeholder value for an index which hasn't been calculated yet. */ 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final static int NOT_CALCULATED = -2; 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Error message presented when a user tries to treat an opaque URI as 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * hierarchical. 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NOT_HIERARCHICAL 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = "This isn't a hierarchical URI."; 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Default encoding. */ 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_ENCODING = "UTF-8"; 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a Uri which parses the given encoded URI string. 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4478aa393b03f6d1f25313c658334e9b86a86a6f61fSimon Schoar * @param uriString an RFC 2396-compliant, encoded URI 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if uriString is null 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Uri for this given uri string 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Uri parse(String uriString) { 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new StringUri(uriString); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a Uri from a file. The URI has the form 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "file://<absolute path>". Encodes path characters with the exception of 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * '/'. 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Example: "file:///tmp/android.txt" 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if file is null 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a Uri for the given file 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Uri fromFile(File file) { 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (file == null) { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new NullPointerException("file"); 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathPart path = PathPart.fromDecoded(file.getAbsolutePath()); 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new HierarchicalUri( 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "file", Part.EMPTY, path, Part.NULL, Part.NULL); 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An implementation which wraps a String URI. This URI can be opaque or 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * hierarchical, but we extend AbstractHierarchicalUri in case we need 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the hierarchical functionality. 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class StringUri extends AbstractHierarchicalUri { 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used in parcelling. */ 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int TYPE_ID = 1; 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** URI string representation. */ 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String uriString; 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private StringUri(String uriString) { 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uriString == null) { 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new NullPointerException("uriString"); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.uriString = uriString; 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Uri readFrom(Parcel parcel) { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new StringUri(parcel.readString()); 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int describeContents() { 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel parcel, int flags) { 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(TYPE_ID); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(uriString); 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Cached scheme separator index. */ 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile int cachedSsi = NOT_CALCULATED; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Finds the first ':'. Returns -1 if none found. */ 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int findSchemeSeparator() { 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cachedSsi == NOT_CALCULATED 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? cachedSsi = uriString.indexOf(':') 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : cachedSsi; 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Cached fragment separator index. */ 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile int cachedFsi = NOT_CALCULATED; 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Finds the first '#'. Returns -1 if none found. */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int findFragmentSeparator() { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cachedFsi == NOT_CALCULATED 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? cachedFsi = uriString.indexOf('#', findSchemeSeparator()) 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : cachedFsi; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isHierarchical() { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ssi = findSchemeSeparator(); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ssi == NOT_FOUND) { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // All relative URIs are hierarchical. 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uriString.length() == ssi + 1) { 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No ssp. 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the ssp starts with a '/', this is hierarchical. 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString.charAt(ssi + 1) == '/'; 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isRelative() { 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note: We return true if the index is 0 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return findSchemeSeparator() == NOT_FOUND; 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile String scheme = NOT_CACHED; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getScheme() { 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean cached = (scheme != NOT_CACHED); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cached ? scheme : (scheme = parseScheme()); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseScheme() { 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ssi = findSchemeSeparator(); 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ssi == NOT_FOUND ? null : uriString.substring(0, ssi); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part ssp; 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getSsp() { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ssp == null ? ssp = Part.fromEncoded(parseSsp()) : ssp; 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedSchemeSpecificPart() { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getSsp().getEncoded(); 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSchemeSpecificPart() { 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getSsp().getDecoded(); 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseSsp() { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ssi = findSchemeSeparator(); 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fsi = findFragmentSeparator(); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Return everything between ssi and fsi. 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fsi == NOT_FOUND 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? uriString.substring(ssi + 1) 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : uriString.substring(ssi + 1, fsi); 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part authority; 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getAuthorityPart() { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (authority == null) { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encodedAuthority 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = parseAuthority(this.uriString, findSchemeSeparator()); 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return authority = Part.fromEncoded(encodedAuthority); 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return authority; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedAuthority() { 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAuthorityPart().getEncoded(); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getAuthority() { 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAuthorityPart().getDecoded(); 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PathPart path; 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PathPart getPathPart() { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path == null 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? path = PathPart.fromEncoded(parsePath()) 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : path; 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getPath() { 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getPathPart().getDecoded(); 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedPath() { 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getPathPart().getEncoded(); 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public List<String> getPathSegments() { 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getPathPart().getPathSegments(); 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parsePath() { 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String uriString = this.uriString; 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ssi = findSchemeSeparator(); 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the URI is absolute. 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ssi > -1) { 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Is there anything after the ':'? 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean schemeOnly = ssi + 1 == uriString.length(); 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (schemeOnly) { 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Opaque URI. 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // A '/' after the ':' means this is hierarchical. 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uriString.charAt(ssi + 1) != '/') { 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Opaque URI. 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // All relative URIs are hierarchical. 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return parsePath(uriString, ssi); 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part query; 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getQueryPart() { 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query == null 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? query = Part.fromEncoded(parseQuery()) : query; 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedQuery() { 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getQueryPart().getEncoded(); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseQuery() { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // It doesn't make sense to cache this index. We only ever 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // calculate it once. 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int qsi = uriString.indexOf('?', findSchemeSeparator()); 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (qsi == NOT_FOUND) { 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fsi = findFragmentSeparator(); 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fsi == NOT_FOUND) { 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString.substring(qsi + 1); 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fsi < qsi) { 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Invalid. 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString.substring(qsi + 1, fsi); 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getQuery() { 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getQueryPart().getDecoded(); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part fragment; 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getFragmentPart() { 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fragment == null 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? fragment = Part.fromEncoded(parseFragment()) : fragment; 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedFragment() { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getFragmentPart().getEncoded(); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseFragment() { 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fsi = findFragmentSeparator(); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fsi == NOT_FOUND ? null : uriString.substring(fsi + 1); 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getFragment() { 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getFragmentPart().getDecoded(); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString; 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Parses an authority out of the given URI string. 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param uriString URI string 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param ssi scheme separator index, -1 for a relative URI 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the authority or null if none is found 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static String parseAuthority(String uriString, int ssi) { 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = uriString.length(); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If "//" follows the scheme separator, we have an authority. 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length > ssi + 2 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && uriString.charAt(ssi + 1) == '/' 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && uriString.charAt(ssi + 2) == '/') { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We have an authority. 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Look for the start of the path, query, or fragment, or the 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // end of the string. 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = ssi + 3; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOOP: while (end < length) { 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (uriString.charAt(end)) { 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '/': // Start of path 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '?': // Start of query 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '#': // Start of fragment 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break LOOP; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end++; 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString.substring(ssi + 3, end); 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Parses a path out of this given URI string. 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param uriString URI string 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param ssi scheme separator index, -1 for a relative URI 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the path 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static String parsePath(String uriString, int ssi) { 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = uriString.length(); 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find start of path. 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pathStart; 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length > ssi + 2 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && uriString.charAt(ssi + 1) == '/' 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && uriString.charAt(ssi + 2) == '/') { 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Skip over authority to path. 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathStart = ssi + 3; 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOOP: while (pathStart < length) { 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (uriString.charAt(pathStart)) { 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '?': // Start of query 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '#': // Start of fragment 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ""; // Empty path. 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '/': // Start of path! 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break LOOP; 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathStart++; 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Path starts immediately after scheme separator. 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathStart = ssi + 1; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find end of path. 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pathEnd = pathStart; 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOOP: while (pathEnd < length) { 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (uriString.charAt(pathEnd)) { 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '?': // Start of query 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case '#': // Start of fragment 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break LOOP; 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathEnd++; 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return uriString.substring(pathStart, pathEnd); 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder buildUpon() { 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isHierarchical()) { 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Builder() 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .scheme(getScheme()) 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .authority(getAuthorityPart()) 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .path(getPathPart()) 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .query(getQueryPart()) 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .fragment(getFragmentPart()); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Builder() 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .scheme(getScheme()) 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .opaquePart(getSsp()) 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .fragment(getFragmentPart()); 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates an opaque Uri from the given components. Encodes the ssp 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which means this method cannot be used to create hierarchical URIs. 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param scheme of the URI 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param ssp scheme-specific-part, everything between the 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scheme separator (':') and the fragment separator ('#'), which will 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * get encoded 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param fragment fragment, everything after the '#', null if undefined, 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will get encoded 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if scheme or ssp is null 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Uri composed of the given scheme, ssp, and fragment 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Builder if you don't want the ssp and fragment to be encoded 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Uri fromParts(String scheme, String ssp, 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String fragment) { 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (scheme == null) { 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new NullPointerException("scheme"); 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ssp == null) { 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new NullPointerException("ssp"); 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new OpaqueUri(scheme, Part.fromDecoded(ssp), 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.fromDecoded(fragment)); 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Opaque URI. 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class OpaqueUri extends Uri { 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used in parcelling. */ 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int TYPE_ID = 2; 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String scheme; 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Part ssp; 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Part fragment; 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OpaqueUri(String scheme, Part ssp, Part fragment) { 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.scheme = scheme; 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.ssp = ssp; 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.fragment = fragment == null ? Part.NULL : fragment; 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Uri readFrom(Parcel parcel) { 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new OpaqueUri( 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.readString(), 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.readFrom(parcel), 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.readFrom(parcel) 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ); 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int describeContents() { 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel parcel, int flags) { 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(TYPE_ID); 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(scheme); 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ssp.writeTo(parcel); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fragment.writeTo(parcel); 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isHierarchical() { 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isRelative() { 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return scheme == null; 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getScheme() { 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.scheme; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedSchemeSpecificPart() { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ssp.getEncoded(); 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSchemeSpecificPart() { 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ssp.getDecoded(); 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getAuthority() { 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedAuthority() { 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getPath() { 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedPath() { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getQuery() { 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedQuery() { 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getFragment() { 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fragment.getDecoded(); 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedFragment() { 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fragment.getEncoded(); 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public List<String> getPathSegments() { 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Collections.emptyList(); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLastPathSegment() { 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getUserInfo() { 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedUserInfo() { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getHost() { 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getPort() { 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile String cachedString = NOT_CACHED; 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean cached = cachedString != NOT_CACHED; 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cached) { 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cachedString; 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder sb = new StringBuilder(); 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(scheme).append(':'); 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append(getEncodedSchemeSpecificPart()); 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fragment.isEmpty()) { 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.append('#').append(fragment.getEncoded()); 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cachedString = sb.toString(); 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder buildUpon() { 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Builder() 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .scheme(this.scheme) 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .opaquePart(this.ssp) 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .fragment(this.fragment); 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wrapper for path segment array. 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class PathSegments extends AbstractList<String> 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project implements RandomAccess { 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final PathSegments EMPTY = new PathSegments(null, 0); 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String[] segments; 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int size; 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathSegments(String[] segments, int size) { 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.segments = segments; 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.size = size; 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String get(int index) { 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index >= size) { 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IndexOutOfBoundsException(); 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return segments[index]; 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int size() { 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.size; 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Builds PathSegments. 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class PathSegmentsBuilder { 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] segments; 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = 0; 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void add(String segment) { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (segments == null) { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segments = new String[4]; 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (size + 1 == segments.length) { 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] expanded = new String[segments.length * 2]; 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(segments, 0, expanded, 0, segments.length); 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segments = expanded; 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segments[size++] = segment; 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathSegments build() { 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (segments == null) { 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return PathSegments.EMPTY; 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new PathSegments(segments, size); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Makes sure this doesn't get reused. 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segments = null; 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Support for hierarchical URIs. 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private abstract static class AbstractHierarchicalUri extends Uri { 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLastPathSegment() { 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: If we haven't parsed all of the segments already, just 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // grab the last one directly so we only allocate one string. 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<String> segments = getPathSegments(); 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = segments.size(); 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (size == 0) { 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return segments.get(size - 1); 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part userInfo; 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getUserInfoPart() { 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return userInfo == null 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? userInfo = Part.fromEncoded(parseUserInfo()) : userInfo; 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final String getEncodedUserInfo() { 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getUserInfoPart().getEncoded(); 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseUserInfo() { 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String authority = getEncodedAuthority(); 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (authority == null) { 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = authority.indexOf('@'); 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end == NOT_FOUND ? null : authority.substring(0, end); 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getUserInfo() { 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getUserInfoPart().getDecoded(); 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile String host = NOT_CACHED; 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getHost() { 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean cached = (host != NOT_CACHED); 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cached ? host 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : (host = parseHost()); 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String parseHost() { 1101fc01794f33057862a361a0d0113630c58befc21bKenny Root String authority = getEncodedAuthority(); 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (authority == null) { 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Parse out user info and then port. 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int userInfoSeparator = authority.indexOf('@'); 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int portSeparator = authority.indexOf(':', userInfoSeparator); 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1110fc01794f33057862a361a0d0113630c58befc21bKenny Root String encodedHost = portSeparator == NOT_FOUND 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? authority.substring(userInfoSeparator + 1) 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : authority.substring(userInfoSeparator + 1, portSeparator); 1113fc01794f33057862a361a0d0113630c58befc21bKenny Root 1114fc01794f33057862a361a0d0113630c58befc21bKenny Root return decode(encodedHost); 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile int port = NOT_CALCULATED; 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getPort() { 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return port == NOT_CALCULATED 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? port = parsePort() 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : port; 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int parsePort() { 1126fc01794f33057862a361a0d0113630c58befc21bKenny Root String authority = getEncodedAuthority(); 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (authority == null) { 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure we look for the port separtor *after* the user info 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // separator. We have URLs with a ':' in the user info. 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int userInfoSeparator = authority.indexOf('@'); 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int portSeparator = authority.indexOf(':', userInfoSeparator); 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (portSeparator == NOT_FOUND) { 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1140fc01794f33057862a361a0d0113630c58befc21bKenny Root String portString = decode(authority.substring(portSeparator + 1)); 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Integer.parseInt(portString); 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOG, "Error parsing port string.", e); 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Hierarchical Uri. 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class HierarchicalUri extends AbstractHierarchicalUri { 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Used in parcelling. */ 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int TYPE_ID = 3; 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1158a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru private final String scheme; // can be null 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Part authority; 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final PathPart path; 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Part query; 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Part fragment; 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private HierarchicalUri(String scheme, Part authority, PathPart path, 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part query, Part fragment) { 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.scheme = scheme; 1167a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru this.authority = Part.nonNull(authority); 1168a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru this.path = path == null ? PathPart.NULL : path; 1169a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru this.query = Part.nonNull(query); 1170a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru this.fragment = Part.nonNull(fragment); 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Uri readFrom(Parcel parcel) { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new HierarchicalUri( 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.readString(), 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.readFrom(parcel), 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathPart.readFrom(parcel), 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.readFrom(parcel), 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Part.readFrom(parcel) 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ); 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int describeContents() { 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel parcel, int flags) { 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(TYPE_ID); 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(scheme); 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project authority.writeTo(parcel); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path.writeTo(parcel); 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project query.writeTo(parcel); 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fragment.writeTo(parcel); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isHierarchical() { 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isRelative() { 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return scheme == null; 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getScheme() { 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return scheme; 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part ssp; 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part getSsp() { 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ssp == null 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? ssp = Part.fromEncoded(makeSchemeSpecificPart()) : ssp; 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedSchemeSpecificPart() { 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getSsp().getEncoded(); 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSchemeSpecificPart() { 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getSsp().getDecoded(); 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates the encoded scheme-specific part from its sub parts. 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String makeSchemeSpecificPart() { 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder builder = new StringBuilder(); 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendSspTo(builder); 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return builder.toString(); 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void appendSspTo(StringBuilder builder) { 1233a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru String encodedAuthority = authority.getEncoded(); 1234a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru if (encodedAuthority != null) { 1235a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru // Even if the authority is "", we still want to append "//". 1236a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru builder.append("//").append(encodedAuthority); 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encodedPath = path.getEncoded(); 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encodedPath != null) { 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append(encodedPath); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1244a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru if (!query.isEmpty()) { 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append('?').append(query.getEncoded()); 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getAuthority() { 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.authority.getDecoded(); 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedAuthority() { 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.authority.getEncoded(); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedPath() { 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.path.getEncoded(); 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getPath() { 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.path.getDecoded(); 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getQuery() { 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.query.getDecoded(); 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedQuery() { 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.query.getEncoded(); 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getFragment() { 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.fragment.getDecoded(); 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncodedFragment() { 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.fragment.getEncoded(); 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public List<String> getPathSegments() { 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this.path.getPathSegments(); 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile String uriString = NOT_CACHED; 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean cached = (uriString != NOT_CACHED); 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cached ? uriString 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : (uriString = makeUriString()); 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String makeUriString() { 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder builder = new StringBuilder(); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (scheme != null) { 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append(scheme).append(':'); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendSspTo(builder); 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1304a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru if (!fragment.isEmpty()) { 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append('#').append(fragment.getEncoded()); 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return builder.toString(); 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder buildUpon() { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Builder() 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .scheme(scheme) 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .authority(authority) 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .path(path) 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .query(query) 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .fragment(fragment); 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper class for building or manipulating URI references. Not safe for 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * concurrent use. 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>An absolute hierarchical URI reference follows the pattern: 13264e8620f868e2490782ebb960404140ea9482c91dBen Dodson * {@code <scheme>://<authority><absolute path>?<query>#<fragment>} 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Relative URI references (which are always hierarchical) follow one 13294e8620f868e2490782ebb960404140ea9482c91dBen Dodson * of two patterns: {@code <relative or absolute path>?<query>#<fragment>} 13304e8620f868e2490782ebb960404140ea9482c91dBen Dodson * or {@code //<authority><absolute path>?<query>#<fragment>} 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>An opaque URI follows this pattern: 13334e8620f868e2490782ebb960404140ea9482c91dBen Dodson * {@code <scheme>:<opaque part>#<fragment>} 13340f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson * 133558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * <p>Use {@link Uri#buildUpon()} to obtain a builder representing an existing URI. 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final class Builder { 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String scheme; 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part opaquePart; 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part authority; 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PathPart path; 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part query; 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part fragment; 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructs a new Builder. 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder() {} 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the scheme. 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param scheme name or {@code null} if this is a relative Uri 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder scheme(String scheme) { 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.scheme = scheme; 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder opaquePart(Part opaquePart) { 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.opaquePart = opaquePart; 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes and sets the given opaque scheme-specific-part. 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param opaquePart decoded opaque part 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder opaquePart(String opaquePart) { 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return opaquePart(Part.fromDecoded(opaquePart)); 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the previously encoded opaque scheme-specific-part. 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param opaquePart encoded opaque part 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder encodedOpaquePart(String opaquePart) { 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return opaquePart(Part.fromEncoded(opaquePart)); 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder authority(Part authority) { 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This URI will be hierarchical. 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.opaquePart = null; 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.authority = authority; 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes and sets the authority. 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder authority(String authority) { 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return authority(Part.fromDecoded(authority)); 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the previously encoded authority. 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder encodedAuthority(String authority) { 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return authority(Part.fromEncoded(authority)); 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder path(PathPart path) { 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This URI will be hierarchical. 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.opaquePart = null; 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.path = path; 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the path. Leaves '/' characters intact but encodes others as 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * necessary. 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>If the path is not null and doesn't start with a '/', and if 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you specify a scheme and/or authority, the builder will prepend the 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given path with a '/'. 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder path(String path) { 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path(PathPart.fromDecoded(path)); 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the previously encoded path. 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>If the path is not null and doesn't start with a '/', and if 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you specify a scheme and/or authority, the builder will prepend the 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given path with a '/'. 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder encodedPath(String path) { 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path(PathPart.fromEncoded(path)); 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes the given segment and appends it to the path. 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder appendPath(String newSegment) { 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path(PathPart.appendDecodedSegment(path, newSegment)); 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Appends the given segment to the path. 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder appendEncodedPath(String newSegment) { 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path(PathPart.appendEncodedSegment(path, newSegment)); 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder query(Part query) { 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This URI will be hierarchical. 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.opaquePart = null; 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.query = query; 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes and sets the query. 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder query(String query) { 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(Part.fromDecoded(query)); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the previously encoded query. 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder encodedQuery(String query) { 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return query(Part.fromEncoded(query)); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder fragment(Part fragment) { 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.fragment = fragment; 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes and sets the fragment. 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder fragment(String fragment) { 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fragment(Part.fromDecoded(fragment)); 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the previously encoded fragment. 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder encodedFragment(String fragment) { 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fragment(Part.fromEncoded(fragment)); 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes the key and value and then appends the parameter to the 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * query string. 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param key which will be encoded 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param value which will be encoded 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Builder appendQueryParameter(String key, String value) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This URI will be hierarchical. 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.opaquePart = null; 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encodedParameter = encode(key, null) + "=" 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + encode(value, null); 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (query == null) { 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project query = Part.fromEncoded(encodedParameter); 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String oldQuery = query.getEncoded(); 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldQuery == null || oldQuery.length() == 0) { 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project query = Part.fromEncoded(encodedParameter); 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project query = Part.fromEncoded(oldQuery + "&" + encodedParameter); 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 152258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * Clears the the previously set query. 152358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson */ 152458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson public Builder clearQuery() { 152558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson return query((Part) null); 152658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 152758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 152858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson /** 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructs a Uri with the current attributes. 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws UnsupportedOperationException if the URI is opaque and the 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scheme is null 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Uri build() { 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (opaquePart != null) { 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (this.scheme == null) { 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new UnsupportedOperationException( 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "An opaque URI must have a scheme."); 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new OpaqueUri(scheme, opaquePart, fragment); 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Hierarchical URIs should not return null for getPath(). 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathPart path = this.path; 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null || path == PathPart.NULL) { 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = PathPart.EMPTY; 15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we have a scheme and/or authority, the path must 15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // be absolute. Prepend it with a '/' if necessary. 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hasSchemeOrAuthority()) { 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = PathPart.makeAbsolute(path); 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new HierarchicalUri( 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project scheme, authority, path, query, fragment); 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean hasSchemeOrAuthority() { 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return scheme != null 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (authority != null && authority != Part.NULL); 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return build().toString(); 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 157358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * Returns a set of the unique names of all query parameters. Iterating 157458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * over the set will return the names in order of their first occurrence. 157558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * 157658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * @throws UnsupportedOperationException if this isn't a hierarchical URI 157758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * 157858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson * @return a set of decoded names 157958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson */ 158058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson public Set<String> getQueryParameterNames() { 158158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (isOpaque()) { 158258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson throw new UnsupportedOperationException(NOT_HIERARCHICAL); 158358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 158458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 158558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson String query = getEncodedQuery(); 158658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (query == null) { 158758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson return Collections.emptySet(); 158858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 158958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 159058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson Set<String> names = new LinkedHashSet<String>(); 159158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int start = 0; 159258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson do { 159358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int next = query.indexOf('&', start); 159458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int end = (next == -1) ? query.length() : next; 159558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 159658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int separator = query.indexOf('=', start); 159758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator > end || separator == -1) { 159858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson separator = end; 159958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 160058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 160158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson String name = query.substring(start, separator); 160258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson names.add(decode(name)); 160358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 160458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson // Move start to end of name. 160558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson start = end + 1; 160658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } while (start < query.length()); 160758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 160858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson return Collections.unmodifiableSet(names); 160958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 161058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 161158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson /** 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Searches the query string for parameter values with the given key. 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param key which will be encoded 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws UnsupportedOperationException if this isn't a hierarchical URI 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if key is null 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a list of decoded values 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public List<String> getQueryParameters(String key) { 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpaque()) { 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new UnsupportedOperationException(NOT_HIERARCHICAL); 16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 162458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (key == null) { 162558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson throw new NullPointerException("key"); 162658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1628a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru String query = getEncodedQuery(); 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (query == null) { 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Collections.emptyList(); 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encodedKey; 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encodedKey = URLEncoder.encode(key, DEFAULT_ENCODING); 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException e) { 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new AssertionError(e); 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<String> values = new ArrayList<String>(); 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = 0; 164358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson do { 164458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int nextAmpersand = query.indexOf('&', start); 164558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int end = nextAmpersand != -1 ? nextAmpersand : query.length(); 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 164758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int separator = query.indexOf('=', start); 164858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator > end || separator == -1) { 164958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson separator = end; 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 165258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator - start == encodedKey.length() 165358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson && query.regionMatches(start, encodedKey, 0, encodedKey.length())) { 165458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator == end) { 165558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson values.add(""); 165658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } else { 165758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson values.add(decode(query.substring(separator + 1, end))); 165858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 166158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson // Move start to end of name. 166258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (nextAmpersand != -1) { 166358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson start = nextAmpersand + 1; 166458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } else { 166558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson break; 166658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 166758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } while (true); 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Collections.unmodifiableList(values); 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Searches the query string for the first value with the given key. 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16754356c95354d28b8ceb1b04e97c53c2ba3b3faa93Narayan Kamath * <p><strong>Warning:</strong> Prior to Jelly Bean, this decoded 167641e0839b136cdeccd2f45de1d9c56240f3933a1eJesse Wilson * the '+' character as '+' rather than ' '. 167741e0839b136cdeccd2f45de1d9c56240f3933a1eJesse Wilson * 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param key which will be encoded 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws UnsupportedOperationException if this isn't a hierarchical URI 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if key is null 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the decoded value or null if no parameter is found 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1683e26450b7142feae9902b432eb01bcd33f3cbd1bdScott Kennedy @Nullable 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getQueryParameter(String key) { 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isOpaque()) { 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new UnsupportedOperationException(NOT_HIERARCHICAL); 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 168870ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick if (key == null) { 1689f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton throw new NullPointerException("key"); 169070ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick } 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 169270ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick final String query = getEncodedQuery(); 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (query == null) { 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 169770ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick final String encodedKey = encode(key, null); 169858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson final int length = query.length(); 169958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int start = 0; 170058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson do { 170158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int nextAmpersand = query.indexOf('&', start); 170258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int end = nextAmpersand != -1 ? nextAmpersand : length; 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 170458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson int separator = query.indexOf('=', start); 170558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator > end || separator == -1) { 170658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson separator = end; 170770ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick } 170858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 170958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator - start == encodedKey.length() 171058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson && query.regionMatches(start, encodedKey, 0, encodedKey.length())) { 171158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (separator == end) { 17120f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson return ""; 171358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } else { 17140f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson String encodedValue = query.substring(separator + 1, end); 1715d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes return UriCodec.decode(encodedValue, true, StandardCharsets.UTF_8, false); 171670ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick } 171758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } 171858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson 171958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson // Move start to end of name. 172058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson if (nextAmpersand != -1) { 172158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson start = nextAmpersand + 1; 1722e41c317348cfe23a78bfd97609c3489c6cc4a786Keith Ito } else { 172358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson break; 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 172558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson } while (true); 172670ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick return null; 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton /** 1730f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * Searches the query string for the first value with the given key and interprets it 1731f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * as a boolean value. "false" and "0" are interpreted as <code>false</code>, everything 1732f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * else is interpreted as <code>true</code>. 1733f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * 1734f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * @param key which will be decoded 1735f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * @param defaultValue the default value to return if there is no query parameter for key 1736f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton * @return the boolean interpretation of the query parameter key 1737f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton */ 1738f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton public boolean getBooleanQueryParameter(String key, boolean defaultValue) { 1739f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton String flag = getQueryParameter(key); 1740f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton if (flag == null) { 1741f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton return defaultValue; 1742f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton } 1743cb64d430627b71221c588ef5f23599dd34a89ee9Elliott Hughes flag = flag.toLowerCase(Locale.ROOT); 1744f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton return (!"false".equals(flag) && !"0".equals(flag)); 1745f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton } 1746f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton 1747ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly /** 1748abc43ddd8ae098de7a56afc55909f904cd933016Jesse Wilson * Return an equivalent URI with a lowercase scheme component. 1749ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * This aligns the Uri with Android best practices for 1750ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * intent filtering. 1751ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * 1752ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * <p>For example, "HTTP://www.android.com" becomes 1753ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * "http://www.android.com" 1754ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * 1755ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * <p>All URIs received from outside Android (such as user input, 1756ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * or external sources like Bluetooth, NFC, or the Internet) should 1757ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * be normalized before they are used to create an Intent. 1758ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * 1759ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * <p class="note">This method does <em>not</em> validate bad URI's, 1760ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * or 'fix' poorly formatted URI's - so do not use it for input validation. 1761ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * A Uri will always be returned, even if the Uri is badly formatted to 1762ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * begin with and a scheme component cannot be found. 1763ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * 1764ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly * @return normalized Uri (never null) 176554de77470de4f605eef7f4b4e01718b301fe275eElliot Waite * @see android.content.Intent#setData 176654de77470de4f605eef7f4b4e01718b301fe275eElliot Waite * @see android.content.Intent#setDataAndNormalize 1767ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly */ 1768abc43ddd8ae098de7a56afc55909f904cd933016Jesse Wilson public Uri normalizeScheme() { 1769ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly String scheme = getScheme(); 1770ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly if (scheme == null) return this; // give up 1771cb64d430627b71221c588ef5f23599dd34a89ee9Elliott Hughes String lowerScheme = scheme.toLowerCase(Locale.ROOT); 1772ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly if (scheme.equals(lowerScheme)) return this; // no change 1773ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly 1774ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly return buildUpon().scheme(lowerScheme).build(); 1775ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly } 1776ccae412deda8b0c165c86f395752c0667a3411a6Nick Pelly 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Identifies a null parcelled Uri. */ 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int NULL_TYPE_ID = 0; 17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reads Uris from Parcels. 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<Uri> CREATOR 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = new Parcelable.Creator<Uri>() { 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Uri createFromParcel(Parcel in) { 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int type = in.readInt(); 17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (type) { 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case NULL_TYPE_ID: return null; 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case StringUri.TYPE_ID: return StringUri.readFrom(in); 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case OpaqueUri.TYPE_ID: return OpaqueUri.readFrom(in); 17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case HierarchicalUri.TYPE_ID: 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HierarchicalUri.readFrom(in); 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17958e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn throw new IllegalArgumentException("Unknown URI type: " + type); 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Uri[] newArray(int size) { 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Uri[size]; 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Writes a Uri to a Parcel. 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param out parcel to write to 18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param uri to write, can be null 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void writeToParcel(Parcel out, Uri uri) { 18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri == null) { 18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.writeInt(NULL_TYPE_ID); 18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri.writeToParcel(out, 0); 18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes characters in the given string as '%'-escaped octets 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers 18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all other characters. 18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param s string to encode 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return an encoded version of s suitable for use as a URI component, 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or null if s is null 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String encode(String s) { 18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encode(s, null); 18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Encodes characters in the given string as '%'-escaped octets 18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers 18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all other characters with the exception of those specified in the 18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * allow argument. 18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param s string to encode 18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param allow set of additional characters to allow in the encoded form, 18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * null if no characters should be skipped 18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return an encoded version of s suitable for use as a URI component, 18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or null if s is null 18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String encode(String s, String allow) { 18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (s == null) { 18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Lazily-initialized buffers. 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder encoded = null; 18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldLength = s.length(); 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This loop alternates between copying over allowed characters and 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // encoding in chunks. This results in fewer method calls and 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allocations than encoding one character at a time. 18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int current = 0; 18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (current < oldLength) { 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Start in "copying" mode where we copy over allowed chars. 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next character which needs to be encoded. 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextToEncode = current; 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (nextToEncode < oldLength 18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && isAllowed(s.charAt(nextToEncode), allow)) { 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextToEncode++; 18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If there's nothing more to encode... 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextToEncode == oldLength) { 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (current == 0) { 18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We didn't need to encode anything! 18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return s; 18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Presumably, we've already done some encoding. 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded.append(s, current, oldLength); 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoded.toString(); 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encoded == null) { 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded = new StringBuilder(); 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nextToEncode > current) { 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Append allowed characters leading up to this point. 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded.append(s, current, nextToEncode); 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // assert nextToEncode == current 18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Switch to "encoding" mode. 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find the next allowed character. 18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project current = nextToEncode; 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int nextAllowed = current + 1; 18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (nextAllowed < oldLength 18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && !isAllowed(s.charAt(nextAllowed), allow)) { 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nextAllowed++; 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Convert the substring to bytes and encode the bytes as 19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // '%'-escaped octets. 19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String toEncode = s.substring(current, nextAllowed); 19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] bytes = toEncode.getBytes(DEFAULT_ENCODING); 19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bytesLength = bytes.length; 19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < bytesLength; i++) { 19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded.append('%'); 19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded.append(HEX_DIGITS[(bytes[i] & 0xf0) >> 4]); 19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoded.append(HEX_DIGITS[bytes[i] & 0xf]); 19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException e) { 19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new AssertionError(e); 19169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project current = nextAllowed; 19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Encoded could still be null at this point if s is empty. 19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoded == null ? s : encoded.toString(); 19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if the given character is allowed. 19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param c character to check 19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param allow characters to allow 19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the character is allowed or false if it should be 19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * encoded 19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean isAllowed(char c, String allow) { 19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (c >= 'A' && c <= 'Z') 19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (c >= 'a' && c <= 'z') 19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (c >= '0' && c <= '9') 19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || "_-!.~'()*".indexOf(c) != NOT_FOUND 19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (allow != null && allow.indexOf(c) != NOT_FOUND); 19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Decodes '%'-escaped octets in the given string using the UTF-8 scheme. 19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Replaces invalid octets with the unicode replacement character 19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ("\\uFFFD"). 19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param s encoded string to decode 19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the given string with escaped octets decoded, or null if 19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * s is null 19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String decode(String s) { 19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (s == null) { 19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1954d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes return UriCodec.decode(s, false, StandardCharsets.UTF_8, false); 19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Support for part implementations. 19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static abstract class AbstractPart { 19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enum which indicates which representation of a given part we have. 19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class Representation { 19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int BOTH = 0; 19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int ENCODED = 1; 19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int DECODED = 2; 19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project volatile String encoded; 19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project volatile String decoded; 19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AbstractPart(String encoded, String decoded) { 19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.encoded = encoded; 19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.decoded = decoded; 19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project abstract String getEncoded(); 19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String getDecoded() { 19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasDecoded = decoded != NOT_CACHED; 19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return hasDecoded ? decoded : (decoded = decode(encoded)); 19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final void writeTo(Parcel parcel) { 19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasEncoded = encoded != NOT_CACHED; 19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasDecoded = decoded != NOT_CACHED; 19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hasEncoded && hasDecoded) { 19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(Representation.BOTH); 19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(encoded); 19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(decoded); 19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (hasEncoded) { 19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(Representation.ENCODED); 20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(encoded); 20019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (hasDecoded) { 20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeInt(Representation.DECODED); 20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parcel.writeString(decoded); 20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 20058e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn throw new IllegalArgumentException("Neither encoded nor decoded"); 20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Immutable wrapper of encoded and decoded versions of a URI part. Lazily 20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * creates the encoded or decoded version from the other. 20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class Part extends AbstractPart { 20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** A part with null values. */ 20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final Part NULL = new EmptyPart(null); 20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** A part with empty strings for values. */ 20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final Part EMPTY = new EmptyPart(""); 20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Part(String encoded, String decoded) { 20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(encoded, decoded); 20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean isEmpty() { 20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String getEncoded() { 20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasEncoded = encoded != NOT_CACHED; 20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return hasEncoded ? encoded : (encoded = encode(decoded)); 20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Part readFrom(Parcel parcel) { 20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int representation = parcel.readInt(); 20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (representation) { 20399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.BOTH: 20409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(parcel.readString(), parcel.readString()); 20419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.ENCODED: 20429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromEncoded(parcel.readString()); 20439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.DECODED: 20449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromDecoded(parcel.readString()); 20459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 20468e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn throw new IllegalArgumentException("Unknown representation: " 20478e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn + representation); 20489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns given part or {@link #NULL} if the given part is null. 20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Part nonNull(Part part) { 20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return part == null ? NULL : part; 20569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a part from the encoded string. 20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoded part string 20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Part fromEncoded(String encoded) { 20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(encoded, NOT_CACHED); 20659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a part from the decoded string. 20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param decoded part string 20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Part fromDecoded(String decoded) { 20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(NOT_CACHED, decoded); 20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a part from the encoded and decoded strings. 20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoded part string 20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param decoded part string 20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static Part from(String encoded, String decoded) { 20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We have to check both encoded and decoded in case one is 20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // NOT_CACHED. 20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encoded == null) { 20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encoded.length() == 0) { 20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return EMPTY; 20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (decoded == null) { 20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (decoded .length() == 0) { 20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return EMPTY; 20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new Part(encoded, decoded); 21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class EmptyPart extends Part { 21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public EmptyPart(String value) { 21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(value, value); 21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean isEmpty() { 21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Immutable wrapper of encoded and decoded versions of a path part. Lazily 21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * creates the encoded or decoded version from the other. 21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class PathPart extends AbstractPart { 21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** A part with null values. */ 21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final PathPart NULL = new PathPart(null, null); 21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** A part with empty strings for values. */ 21259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final PathPart EMPTY = new PathPart("", ""); 21269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PathPart(String encoded, String decoded) { 21289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(encoded, decoded); 21299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String getEncoded() { 21329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 21339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasEncoded = encoded != NOT_CACHED; 21349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't encode '/'. 21369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return hasEncoded ? encoded : (encoded = encode(decoded, "/")); 21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Cached path segments. This doesn't need to be volatile--we don't 21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * care if other threads see the result. 21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PathSegments pathSegments; 21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the individual path segments. Parses them if necessary. 21479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 21489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return parsed path segments or null if this isn't a hierarchical 21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * URI 21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 21519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathSegments getPathSegments() { 21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pathSegments != null) { 21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pathSegments; 21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = getEncoded(); 21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null) { 21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pathSegments = PathSegments.EMPTY; 21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PathSegmentsBuilder segmentBuilder = new PathSegmentsBuilder(); 21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previous = 0; 21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int current; 21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((current = path.indexOf('/', previous)) > -1) { 21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This check keeps us from adding a segment if the path starts 21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // '/' and an empty segment for "//". 21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previous < current) { 21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String decodedSegment 21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = decode(path.substring(previous, current)); 21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segmentBuilder.add(decodedSegment); 21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previous = current + 1; 21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add in the final path segment. 21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previous < path.length()) { 21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project segmentBuilder.add(decode(path.substring(previous))); 21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pathSegments = segmentBuilder.build(); 21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart appendEncodedSegment(PathPart oldPart, 21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String newSegment) { 21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If there is no old path, should we make the new path relative 21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // or absolute? I pick absolute. 21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldPart == null) { 21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No old path. 21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromEncoded("/" + newSegment); 21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String oldPath = oldPart.getEncoded(); 21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldPath == null) { 21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldPath = ""; 21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldPathLength = oldPath.length(); 22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String newPath; 22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldPathLength == 0) { 22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No old path. 22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newPath = "/" + newSegment; 22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (oldPath.charAt(oldPathLength - 1) == '/') { 22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newPath = oldPath + newSegment; 22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newPath = oldPath + "/" + newSegment; 22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromEncoded(newPath); 22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart appendDecodedSegment(PathPart oldPart, String decoded) { 22159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encoded = encode(decoded); 22169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Should we reuse old PathSegments? Probably not. 22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return appendEncodedSegment(oldPart, encoded); 22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart readFrom(Parcel parcel) { 22229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int representation = parcel.readInt(); 22239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (representation) { 22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.BOTH: 22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(parcel.readString(), parcel.readString()); 22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.ENCODED: 22279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromEncoded(parcel.readString()); 22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case Representation.DECODED: 22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return fromDecoded(parcel.readString()); 22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 22318e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn throw new IllegalArgumentException("Bad representation: " + representation); 22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a path from the encoded string. 22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoded part string 22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart fromEncoded(String encoded) { 22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(encoded, NOT_CACHED); 22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a path from the decoded string. 22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param decoded part string 22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart fromDecoded(String decoded) { 22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return from(NOT_CACHED, decoded); 22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a path from the encoded and decoded strings. 22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoded part string 22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param decoded part string 22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart from(String encoded, String decoded) { 22609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encoded == null) { 22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (encoded.length() == 0) { 22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return EMPTY; 22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new PathPart(encoded, decoded); 22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prepends path values with "/" if they're present, not empty, and 22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * they don't already start with "/". 22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PathPart makeAbsolute(PathPart oldPart) { 22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean encodedCached = oldPart.encoded != NOT_CACHED; 22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We don't care which version we use, and we don't want to force 22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unneccessary encoding/decoding. 22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String oldPath = encodedCached ? oldPart.encoded : oldPart.decoded; 22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldPath == null || oldPath.length() == 0 22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || oldPath.startsWith("/")) { 22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return oldPart; 22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Prepend encoded string if present. 22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String newEncoded = encodedCached 22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? "/" + oldPart.encoded : NOT_CACHED; 22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Prepend decoded string if present. 22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("StringEquality") 22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean decodedCached = oldPart.decoded != NOT_CACHED; 22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String newDecoded = decodedCached 22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? "/" + oldPart.decoded 22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : NOT_CACHED; 22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new PathPart(newEncoded, newDecoded); 23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a new Uri by appending an already-encoded path segment to a 23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * base Uri. 23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param baseUri Uri to append path segment to 23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pathSegment encoded path segment to append 23090f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson * @return a new Uri based on baseUri with the given segment appended to 23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the path 23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws NullPointerException if baseUri is null 23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Uri withAppendedPath(Uri baseUri, String pathSegment) { 23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Builder builder = baseUri.buildUpon(); 23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder = builder.appendEncodedPath(pathSegment); 23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return builder.build(); 23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 231865c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey 231965c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey /** 232065c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * If this {@link Uri} is {@code file://}, then resolve and return its 232165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * canonical path. Also fixes legacy emulated storage paths so they are 232265c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * usable across user boundaries. Should always be called from the app 232365c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * process before sending elsewhere. 232465c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * 232565c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey * @hide 232665c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey */ 232765c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey public Uri getCanonicalUri() { 232865c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey if ("file".equals(getScheme())) { 232965c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey final String canonicalPath; 233065c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey try { 233165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey canonicalPath = new File(getPath()).getCanonicalPath(); 233265c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } catch (IOException e) { 233365c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey return this; 233465c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } 233565c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey 233665c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey if (Environment.isExternalStorageEmulated()) { 233765c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey final String legacyPath = Environment.getLegacyExternalStorageDirectory() 233865c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey .toString(); 233965c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey 234065c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey // Splice in user-specific path when legacy path is found 234165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey if (canonicalPath.startsWith(legacyPath)) { 234265c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey return Uri.fromFile(new File( 234365c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey Environment.getExternalStorageDirectory().toString(), 234465c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey canonicalPath.substring(legacyPath.length() + 1))); 234565c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } 234665c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } 234765c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey 234865c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey return Uri.fromFile(new File(canonicalPath)); 234965c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } else { 235065c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey return this; 235165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } 235265c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey } 2353a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey 2354a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey /** 2355a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey * If this is a {@code file://} Uri, it will be reported to 2356a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey * {@link StrictMode}. 2357a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey * 2358a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey * @hide 2359a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey */ 2360a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey public void checkFileUriExposed(String location) { 2361fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey if ("file".equals(getScheme()) 2362fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey && (getPath() != null) && !getPath().startsWith("/system/")) { 2363344744b49633a7f8aa0c8e43469bbfcf9d8e2cabJeff Sharkey StrictMode.onFileUriExposed(this, location); 2364a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey } 2365a14acd20b8d563319ea1a5974dca0e9a29f0aaefJeff Sharkey } 2366846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 2367846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey /** 2368fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey * If this is a {@code content://} Uri without access flags, it will be 2369fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey * reported to {@link StrictMode}. 2370fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey * 2371fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey * @hide 2372fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey */ 2373fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey public void checkContentUriWithoutPermission(String location, int flags) { 2374fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey if ("content".equals(getScheme()) && !Intent.isAccessUriMode(flags)) { 2375fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey StrictMode.onContentUriWithoutPermission(this, location); 2376fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey } 2377fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey } 2378fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey 2379fb833f38a0c9a27b55784f2bf3dcd7aa7d652157Jeff Sharkey /** 2380846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey * Test if this is a path prefix match against the given Uri. Verifies that 2381846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey * scheme, authority, and atomic path segments match. 2382846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey * 2383846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey * @hide 2384846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey */ 2385846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey public boolean isPathPrefixMatch(Uri prefix) { 2386846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey if (!Objects.equals(getScheme(), prefix.getScheme())) return false; 2387846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey if (!Objects.equals(getAuthority(), prefix.getAuthority())) return false; 2388846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 2389846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey List<String> seg = getPathSegments(); 2390846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey List<String> prefixSeg = prefix.getPathSegments(); 2391846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 2392846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey final int prefixSize = prefixSeg.size(); 2393846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey if (seg.size() < prefixSize) return false; 2394846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 2395846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey for (int i = 0; i < prefixSize; i++) { 2396846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey if (!Objects.equals(seg.get(i), prefixSeg.get(i))) { 2397846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey return false; 2398846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey } 2399846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey } 2400846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey 2401846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey return true; 2402846318a3250fa95f47a9decfbffb05a31dbd0006Jeff Sharkey } 24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2404