Uri.java revision 0f28af209ac877091f4a096f7553f02a0b401596
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
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.URLEncoder;
250f28af209ac877091f4a096f7553f02a0b401596Jesse Wilsonimport java.nio.charset.Charsets;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.AbstractList;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Collections;
2958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodsonimport java.util.LinkedHashSet;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.RandomAccess;
3258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodsonimport java.util.Set;
330f28af209ac877091f4a096f7553f02a0b401596Jesse Wilsonimport libcore.net.UriCodec;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Immutable URI reference. A URI reference includes a URI and a fragment, the
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * component of the URI following a '#'. Builds and parses URI references
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which conform to
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <a href="http://www.faqs.org/rfcs/rfc2396.html">RFC 2396</a>.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>In the interest of performance, this class performs little to no
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * validation. Behavior is undefined for invalid input. This class is very
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * forgiving--in the face of invalid input, it will return garbage
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rather than throw an exception unless otherwise specified.
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class Uri implements Parcelable, Comparable<Uri> {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    This class aims to do as little up front work as possible. To accomplish
5158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson    that, we vary the implementation depending on what the user passes in.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    For example, we have one implementation if the user passes in a
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    URI string (StringUri) and another if the user passes in the
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    individual components (OpaqueUri).
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *Concurrency notes*: Like any truly immutable object, this class is safe
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for concurrent use. This class uses a caching pattern in some places where
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    it doesn't use volatile or synchronized. This is safe to do with ints
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    because getting or setting an int is atomic. It's safe to do with a String
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    because the internal fields are final and the memory model guarantees other
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    threads won't see a partially initialized instance. We are not guaranteed
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    that some threads will immediately see changes from other threads on
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    certain platforms, but we don't mind if those threads reconstruct the
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    cached result. As a result, we get thread safe caching with no concurrency
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    overhead, which means the most common case, access from a single thread,
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    is as fast as possible.
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    From the Java Language spec.:
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    "17.5 Final Field Semantics
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ... when the object is seen by another thread, that thread will always
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    see the correctly constructed version of that object's final fields.
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    It will also see versions of any object or array referenced by
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    those final fields that are at least as up-to-date as the final fields
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    are."
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    In that same vein, all non-transient fields within Uri
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    implementations should be final and immutable so as to ensure true
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    immutability for clients even when they don't use proper concurrency
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    control.
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    For reference, from RFC 2396:
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    "4.3. Parsing a URI Reference
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       A URI reference is typically parsed according to the four main
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       components and fragment identifier in order to determine what
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       components are present and whether the reference is relative or
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       absolute.  The individual components are then parsed for their
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       subparts and, if not opaque, to verify their validity.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       Although the BNF defines what is allowed in each component, it is
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       ambiguous in terms of differentiating between an authority component
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       and a path component that begins with two slash characters.  The
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       greedy algorithm is used for disambiguation: the left-most matching
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       rule soaks up as much of the URI reference string as it is capable of
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       matching.  In other words, the authority component wins."
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    The "four main components" of a hierarchical URI consist of
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    <scheme>://<authority><path>?<query>
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Log tag. */
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String LOG = Uri.class.getSimpleName();
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
109a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * NOTE: EMPTY accesses this field during its own initialization, so this
110a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * field *must* be initialized first, or else EMPTY will see a null value!
111a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     *
112a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * Placeholder for strings which haven't been cached. This enables us
113a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * to cache null. We intentionally create a new String instance so we can
114a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * compare its identity and there is no chance we will confuse it with
115a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     * user data.
116a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru     */
117a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    @SuppressWarnings("RedundantStringConstructorCall")
118a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    private static final String NOT_CACHED = new String("NOT CACHED");
119a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru
120a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru    /**
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The empty URI, equivalent to "".
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Uri EMPTY = new HierarchicalUri(null, Part.NULL,
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PathPart.EMPTY, Part.NULL, Part.NULL);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Prevents external subclassing.
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri() {}
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if this URI is hierarchical like "http://google.com".
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Absolute URIs are hierarchical if the scheme-specific part starts with
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a '/'. Relative URIs are always hierarchical.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract boolean isHierarchical();
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if this URI is opaque like "mailto:nobody@google.com". The
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * scheme-specific part of an opaque URI cannot start with a '/'.
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isOpaque() {
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return !isHierarchical();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if this URI is relative, i.e. if it doesn't contain an
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * explicit scheme.
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if this URI is relative, false if it's absolute
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract boolean isRelative();
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if this URI is absolute, i.e. if it contains an
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * explicit scheme.
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if this URI is absolute, false if it's relative
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isAbsolute() {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return !isRelative();
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the scheme of this URI. Example: "http"
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the scheme or null if this is a relative URI
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getScheme();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the scheme-specific part of this URI, i.e. everything between the
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * scheme separator ':' and the fragment separator '#'. If this is a
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * relative URI, this method returns the entire URI. Decodes escaped octets.
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Example: "//www.google.com/search?q=android"
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded scheme-specific-part
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getSchemeSpecificPart();
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the scheme-specific part of this URI, i.e. everything between the
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * scheme separator ':' and the fragment separator '#'. If this is a
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * relative URI, this method returns the entire URI. Leaves escaped octets
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * intact.
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Example: "//www.google.com/search?q=android"
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded scheme-specific-part
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedSchemeSpecificPart();
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded authority part of this URI. For
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * server addresses, the authority is structured as follows:
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@code [ userinfo '@' ] host [ ':' port ]}
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Examples: "google.com", "bob@google.com:80"
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the authority for this URI or null if not present
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getAuthority();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded authority part of this URI. For
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * server addresses, the authority is structured as follows:
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@code [ userinfo '@' ] host [ ':' port ]}
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Examples: "google.com", "bob@google.com:80"
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the authority for this URI or null if not present
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedAuthority();
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded user information from the authority.
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, if the authority is "nobody@google.com", this method will
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * return "nobody".
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the user info for this URI or null if not present
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getUserInfo();
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded user information from the authority.
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For example, if the authority is "nobody@google.com", this method will
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * return "nobody".
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the user info for this URI or null if not present
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedUserInfo();
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded host from the authority for this URI. For example,
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if the authority is "bob@google.com", this method will return
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "google.com".
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the host for this URI or null if not present
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getHost();
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the port from the authority for this URI. For example,
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if the authority is "google.com:80", this method will return 80.
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the port for this URI or -1 if invalid or not present
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getPort();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded path.
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded path, or null if this is not a hierarchical URI
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (like "mailto:nobody@google.com") or the URI is invalid
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getPath();
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded path.
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the encoded path, or null if this is not a hierarchical URI
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (like "mailto:nobody@google.com") or the URI is invalid
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedPath();
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded query component from this URI. The query comes after
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the query separator ('?') and before the fragment separator ('#'). This
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method would return "q=android" for
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "http://www.google.com/search?q=android".
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded query or null if there isn't one
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getQuery();
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded query component from this URI. The query comes after
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the query separator ('?') and before the fragment separator ('#'). This
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method would return "q=android" for
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "http://www.google.com/search?q=android".
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the encoded query or null if there isn't one
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedQuery();
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded fragment part of this URI, everything after the '#'.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded fragment or null if there isn't one
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getFragment();
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the encoded fragment part of this URI, everything after the '#'.
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the encoded fragment or null if there isn't one
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getEncodedFragment();
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded path segments.
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return decoded path segments, each without a leading or trailing '/'
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract List<String> getPathSegments();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the decoded last segment in the path.
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded last segment or null if the path is empty
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String getLastPathSegment();
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Compares this Uri to another object for equality. Returns true if the
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * encoded string representations of this Uri and the given Uri are
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * equal. Case counts. Paths are not normalized. If one Uri specifies a
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * default port explicitly and the other leaves it implicit, they will not
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be considered equal.
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean equals(Object o) {
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!(o instanceof Uri)) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Uri other = (Uri) o;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return toString().equals(other.toString());
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hashes the encoded string represention of this Uri consistently with
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #equals(Object)}.
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int hashCode() {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return toString().hashCode();
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Compares the string representation of this Uri with that of
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * another.
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int compareTo(Uri other) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return toString().compareTo(other.toString());
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the encoded string representation of this URI.
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Example: "http://google.com/"
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract String toString();
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn     * Return a string representation of the URI that is safe to print
35690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn     * to logs and other places where PII should be avoided.
35790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn     * @hide
35890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn     */
35990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn    public String toSafeString() {
36090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        String scheme = getScheme();
36190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        String ssp = getSchemeSpecificPart();
36290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        if (scheme != null) {
36390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn            if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
36490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                    || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
36590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                    || scheme.equalsIgnoreCase("mailto")) {
36690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                StringBuilder builder = new StringBuilder(64);
36790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                builder.append(scheme);
36890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                builder.append(':');
36990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                if (ssp != null) {
37090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                    for (int i=0; i<ssp.length(); i++) {
37190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                        char c = ssp.charAt(i);
37290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                        if (c == '-' || c == '@' || c == '.') {
37390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                            builder.append(c);
37490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                        } else {
37590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                            builder.append('x');
37690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                        }
37790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                    }
37890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                }
37990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn                return builder.toString();
38090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn            }
38190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        }
38290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        // Not a sensitive scheme, but let's still be conservative about
38390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        // the data we include -- only the ssp, not the query params or
38490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        // fragment, because those can often have sensitive info.
38590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        StringBuilder builder = new StringBuilder(64);
38690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        if (scheme != null) {
38790c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn            builder.append(scheme);
38890c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn            builder.append(':');
38990c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        }
39090c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        if (ssp != null) {
39190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn            builder.append(ssp);
39290c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        }
39390c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn        return builder.toString();
39490c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn    }
39590c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn
39690c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn    /**
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs a new builder, copying the attributes from this Uri.
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract Builder buildUpon();
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Index of a component which was not found. */
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int NOT_FOUND = -1;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Placeholder value for an index which hasn't been calculated yet. */
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int NOT_CALCULATED = -2;
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Error message presented when a user tries to treat an opaque URI as
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * hierarchical.
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String NOT_HIERARCHICAL
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = "This isn't a hierarchical URI.";
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Default encoding. */
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String DEFAULT_ENCODING = "UTF-8";
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a Uri which parses the given encoded URI string.
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4208aa393b03f6d1f25313c658334e9b86a86a6f61fSimon Schoar     * @param uriString an RFC 2396-compliant, encoded URI
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if uriString is null
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Uri for this given uri string
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Uri parse(String uriString) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new StringUri(uriString);
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a Uri from a file. The URI has the form
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "file://<absolute path>". Encodes path characters with the exception of
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * '/'.
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Example: "file:///tmp/android.txt"
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if file is null
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a Uri for the given file
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Uri fromFile(File file) {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (file == null) {
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException("file");
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PathPart path = PathPart.fromDecoded(file.getAbsolutePath());
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new HierarchicalUri(
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "file", Part.EMPTY, path, Part.NULL, Part.NULL);
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * An implementation which wraps a String URI. This URI can be opaque or
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * hierarchical, but we extend AbstractHierarchicalUri in case we need
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the hierarchical functionality.
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class StringUri extends AbstractHierarchicalUri {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Used in parcelling. */
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final int TYPE_ID = 1;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** URI string representation. */
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final String uriString;
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private StringUri(String uriString) {
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uriString == null) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new NullPointerException("uriString");
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.uriString = uriString;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Uri readFrom(Parcel parcel) {
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new StringUri(parcel.readString());
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int describeContents() {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel parcel, int flags) {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeInt(TYPE_ID);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeString(uriString);
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Cached scheme separator index. */
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile int cachedSsi = NOT_CALCULATED;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Finds the first ':'. Returns -1 if none found. */
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int findSchemeSeparator() {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cachedSsi == NOT_CALCULATED
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? cachedSsi = uriString.indexOf(':')
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : cachedSsi;
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Cached fragment separator index. */
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile int cachedFsi = NOT_CALCULATED;
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Finds the first '#'. Returns -1 if none found. */
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int findFragmentSeparator() {
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cachedFsi == NOT_CALCULATED
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? cachedFsi = uriString.indexOf('#', findSchemeSeparator())
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : cachedFsi;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isHierarchical() {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ssi = findSchemeSeparator();
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ssi == NOT_FOUND) {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // All relative URIs are hierarchical.
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uriString.length() == ssi + 1) {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // No ssp.
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the ssp starts with a '/', this is hierarchical.
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uriString.charAt(ssi + 1) == '/';
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isRelative() {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Note: We return true if the index is 0
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return findSchemeSeparator() == NOT_FOUND;
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile String scheme = NOT_CACHED;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getScheme() {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean cached = (scheme != NOT_CACHED);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cached ? scheme : (scheme = parseScheme());
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseScheme() {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ssi = findSchemeSeparator();
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ssi == NOT_FOUND ? null : uriString.substring(0, ssi);
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part ssp;
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getSsp() {
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ssp == null ? ssp = Part.fromEncoded(parseSsp()) : ssp;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedSchemeSpecificPart() {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getSsp().getEncoded();
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getSchemeSpecificPart() {
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getSsp().getDecoded();
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseSsp() {
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ssi = findSchemeSeparator();
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int fsi = findFragmentSeparator();
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Return everything between ssi and fsi.
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fsi == NOT_FOUND
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? uriString.substring(ssi + 1)
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : uriString.substring(ssi + 1, fsi);
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part authority;
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getAuthorityPart() {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (authority == null) {
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String encodedAuthority
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        = parseAuthority(this.uriString, findSchemeSeparator());
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return authority = Part.fromEncoded(encodedAuthority);
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return authority;
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedAuthority() {
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAuthorityPart().getEncoded();
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getAuthority() {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAuthorityPart().getDecoded();
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PathPart path;
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PathPart getPathPart() {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path == null
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? path = PathPart.fromEncoded(parsePath())
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : path;
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getPath() {
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getPathPart().getDecoded();
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedPath() {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getPathPart().getEncoded();
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public List<String> getPathSegments() {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getPathPart().getPathSegments();
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parsePath() {
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String uriString = this.uriString;
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ssi = findSchemeSeparator();
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the URI is absolute.
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ssi > -1) {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Is there anything after the ':'?
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean schemeOnly = ssi + 1 == uriString.length();
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (schemeOnly) {
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Opaque URI.
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return null;
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // A '/' after the ':' means this is hierarchical.
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (uriString.charAt(ssi + 1) != '/') {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Opaque URI.
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return null;
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // All relative URIs are hierarchical.
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return parsePath(uriString, ssi);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part query;
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getQueryPart() {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return query == null
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? query = Part.fromEncoded(parseQuery()) : query;
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedQuery() {
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getQueryPart().getEncoded();
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseQuery() {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // It doesn't make sense to cache this index. We only ever
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // calculate it once.
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int qsi = uriString.indexOf('?', findSchemeSeparator());
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (qsi == NOT_FOUND) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int fsi = findFragmentSeparator();
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fsi == NOT_FOUND) {
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return uriString.substring(qsi + 1);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fsi < qsi) {
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Invalid.
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uriString.substring(qsi + 1, fsi);
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getQuery() {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getQueryPart().getDecoded();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part fragment;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getFragmentPart() {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fragment == null
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? fragment = Part.fromEncoded(parseFragment()) : fragment;
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedFragment() {
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getFragmentPart().getEncoded();
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseFragment() {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int fsi = findFragmentSeparator();
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fsi == NOT_FOUND ? null : uriString.substring(fsi + 1);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getFragment() {
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getFragmentPart().getDecoded();
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uriString;
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Parses an authority out of the given URI string.
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param uriString URI string
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param ssi scheme separator index, -1 for a relative URI
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the authority or null if none is found
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static String parseAuthority(String uriString, int ssi) {
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int length = uriString.length();
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If "//" follows the scheme separator, we have an authority.
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (length > ssi + 2
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && uriString.charAt(ssi + 1) == '/'
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && uriString.charAt(ssi + 2) == '/') {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We have an authority.
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Look for the start of the path, query, or fragment, or the
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // end of the string.
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int end = ssi + 3;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOOP: while (end < length) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    switch (uriString.charAt(end)) {
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '/': // Start of path
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '?': // Start of query
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '#': // Start of fragment
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break LOOP;
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    end++;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return uriString.substring(ssi + 3, end);
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Parses a path out of this given URI string.
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param uriString URI string
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param ssi scheme separator index, -1 for a relative URI
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the path
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static String parsePath(String uriString, int ssi) {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int length = uriString.length();
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find start of path.
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pathStart;
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (length > ssi + 2
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && uriString.charAt(ssi + 1) == '/'
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && uriString.charAt(ssi + 2) == '/') {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Skip over authority to path.
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pathStart = ssi + 3;
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LOOP: while (pathStart < length) {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    switch (uriString.charAt(pathStart)) {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '?': // Start of query
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '#': // Start of fragment
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return ""; // Empty path.
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        case '/': // Start of path!
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break LOOP;
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pathStart++;
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Path starts immediately after scheme separator.
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pathStart = ssi + 1;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find end of path.
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pathEnd = pathStart;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOOP: while (pathEnd < length) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (uriString.charAt(pathEnd)) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case '?': // Start of query
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case '#': // Start of fragment
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break LOOP;
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pathEnd++;
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uriString.substring(pathStart, pathEnd);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder buildUpon() {
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isHierarchical()) {
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new Builder()
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .scheme(getScheme())
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .authority(getAuthorityPart())
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .path(getPathPart())
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .query(getQueryPart())
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .fragment(getFragmentPart());
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new Builder()
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .scheme(getScheme())
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .opaquePart(getSsp())
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .fragment(getFragmentPart());
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates an opaque Uri from the given components. Encodes the ssp
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * which means this method cannot be used to create hierarchical URIs.
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param scheme of the URI
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param ssp scheme-specific-part, everything between the
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  scheme separator (':') and the fragment separator ('#'), which will
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  get encoded
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fragment fragment, everything after the '#', null if undefined,
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  will get encoded
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if scheme or ssp is null
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Uri composed of the given scheme, ssp, and fragment
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see Builder if you don't want the ssp and fragment to be encoded
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Uri fromParts(String scheme, String ssp,
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String fragment) {
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scheme == null) {
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException("scheme");
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ssp == null) {
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException("ssp");
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new OpaqueUri(scheme, Part.fromDecoded(ssp),
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.fromDecoded(fragment));
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Opaque URI.
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class OpaqueUri extends Uri {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Used in parcelling. */
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final int TYPE_ID = 2;
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final String scheme;
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Part ssp;
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Part fragment;
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private OpaqueUri(String scheme, Part ssp, Part fragment) {
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.scheme = scheme;
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.ssp = ssp;
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.fragment = fragment == null ? Part.NULL : fragment;
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Uri readFrom(Parcel parcel) {
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new OpaqueUri(
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.readString(),
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.readFrom(parcel),
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.readFrom(parcel)
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            );
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int describeContents() {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel parcel, int flags) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeInt(TYPE_ID);
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeString(scheme);
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ssp.writeTo(parcel);
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fragment.writeTo(parcel);
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isHierarchical() {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isRelative() {
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return scheme == null;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getScheme() {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.scheme;
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedSchemeSpecificPart() {
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ssp.getEncoded();
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getSchemeSpecificPart() {
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ssp.getDecoded();
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getAuthority() {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedAuthority() {
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getPath() {
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedPath() {
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getQuery() {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedQuery() {
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getFragment() {
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fragment.getDecoded();
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedFragment() {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fragment.getEncoded();
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public List<String> getPathSegments() {
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Collections.emptyList();
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getLastPathSegment() {
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getUserInfo() {
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedUserInfo() {
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getHost() {
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getPort() {
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile String cachedString = NOT_CACHED;
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean cached = cachedString != NOT_CACHED;
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cached) {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return cachedString;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder sb = new StringBuilder();
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(scheme).append(':');
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(getEncodedSchemeSpecificPart());
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!fragment.isEmpty()) {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append('#').append(fragment.getEncoded());
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cachedString = sb.toString();
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder buildUpon() {
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new Builder()
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .scheme(this.scheme)
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .opaquePart(this.ssp)
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .fragment(this.fragment);
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Wrapper for path segment array.
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class PathSegments extends AbstractList<String>
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            implements RandomAccess {
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final PathSegments EMPTY = new PathSegments(null, 0);
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String[] segments;
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int size;
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PathSegments(String[] segments, int size) {
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.segments = segments;
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.size = size;
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String get(int index) {
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index >= size) {
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IndexOutOfBoundsException();
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return segments[index];
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int size() {
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.size;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Builds PathSegments.
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class PathSegmentsBuilder {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String[] segments;
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int size = 0;
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void add(String segment) {
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (segments == null) {
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segments = new String[4];
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (size + 1 == segments.length) {
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String[] expanded = new String[segments.length * 2];
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(segments, 0, expanded, 0, segments.length);
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segments = expanded;
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            segments[size++] = segment;
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PathSegments build() {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (segments == null) {
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return PathSegments.EMPTY;
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new PathSegments(segments, size);
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Makes sure this doesn't get reused.
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segments = null;
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Support for hierarchical URIs.
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private abstract static class AbstractHierarchicalUri extends Uri {
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getLastPathSegment() {
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: If we haven't parsed all of the segments already, just
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // grab the last one directly so we only allocate one string.
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            List<String> segments = getPathSegments();
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = segments.size();
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (size == 0) {
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return segments.get(size - 1);
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part userInfo;
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getUserInfoPart() {
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return userInfo == null
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? userInfo = Part.fromEncoded(parseUserInfo()) : userInfo;
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final String getEncodedUserInfo() {
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getUserInfoPart().getEncoded();
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseUserInfo() {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String authority = getEncodedAuthority();
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (authority == null) {
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int end = authority.indexOf('@');
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return end == NOT_FOUND ? null : authority.substring(0, end);
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getUserInfo() {
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getUserInfoPart().getDecoded();
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile String host = NOT_CACHED;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getHost() {
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean cached = (host != NOT_CACHED);
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cached ? host
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : (host = parseHost());
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String parseHost() {
1074fc01794f33057862a361a0d0113630c58befc21bKenny Root            String authority = getEncodedAuthority();
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (authority == null) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Parse out user info and then port.
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int userInfoSeparator = authority.indexOf('@');
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int portSeparator = authority.indexOf(':', userInfoSeparator);
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1083fc01794f33057862a361a0d0113630c58befc21bKenny Root            String encodedHost = portSeparator == NOT_FOUND
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? authority.substring(userInfoSeparator + 1)
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : authority.substring(userInfoSeparator + 1, portSeparator);
1086fc01794f33057862a361a0d0113630c58befc21bKenny Root
1087fc01794f33057862a361a0d0113630c58befc21bKenny Root            return decode(encodedHost);
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile int port = NOT_CALCULATED;
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getPort() {
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return port == NOT_CALCULATED
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? port = parsePort()
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : port;
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int parsePort() {
1099fc01794f33057862a361a0d0113630c58befc21bKenny Root            String authority = getEncodedAuthority();
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (authority == null) {
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure we look for the port separtor *after* the user info
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // separator. We have URLs with a ':' in the user info.
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int userInfoSeparator = authority.indexOf('@');
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int portSeparator = authority.indexOf(':', userInfoSeparator);
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (portSeparator == NOT_FOUND) {
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1113fc01794f33057862a361a0d0113630c58befc21bKenny Root            String portString = decode(authority.substring(portSeparator + 1));
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Integer.parseInt(portString);
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (NumberFormatException e) {
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(LOG, "Error parsing port string.", e);
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return -1;
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hierarchical Uri.
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class HierarchicalUri extends AbstractHierarchicalUri {
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Used in parcelling. */
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final int TYPE_ID = 3;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1131a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru        private final String scheme; // can be null
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Part authority;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final PathPart path;
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Part query;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final Part fragment;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private HierarchicalUri(String scheme, Part authority, PathPart path,
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part query, Part fragment) {
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.scheme = scheme;
1140a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            this.authority = Part.nonNull(authority);
1141a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            this.path = path == null ? PathPart.NULL : path;
1142a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            this.query = Part.nonNull(query);
1143a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            this.fragment = Part.nonNull(fragment);
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Uri readFrom(Parcel parcel) {
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new HierarchicalUri(
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.readString(),
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.readFrom(parcel),
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PathPart.readFrom(parcel),
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.readFrom(parcel),
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Part.readFrom(parcel)
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            );
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int describeContents() {
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel parcel, int flags) {
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeInt(TYPE_ID);
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parcel.writeString(scheme);
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            authority.writeTo(parcel);
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            path.writeTo(parcel);
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            query.writeTo(parcel);
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fragment.writeTo(parcel);
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isHierarchical() {
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isRelative() {
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return scheme == null;
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getScheme() {
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return scheme;
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part ssp;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part getSsp() {
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ssp == null
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? ssp = Part.fromEncoded(makeSchemeSpecificPart()) : ssp;
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedSchemeSpecificPart() {
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getSsp().getEncoded();
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getSchemeSpecificPart() {
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getSsp().getDecoded();
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates the encoded scheme-specific part from its sub parts.
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String makeSchemeSpecificPart() {
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder builder = new StringBuilder();
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            appendSspTo(builder);
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return builder.toString();
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void appendSspTo(StringBuilder builder) {
1206a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            String encodedAuthority = authority.getEncoded();
1207a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            if (encodedAuthority != null) {
1208a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru                // Even if the authority is "", we still want to append "//".
1209a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru                builder.append("//").append(encodedAuthority);
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String encodedPath = path.getEncoded();
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encodedPath != null) {
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                builder.append(encodedPath);
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1217a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            if (!query.isEmpty()) {
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                builder.append('?').append(query.getEncoded());
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getAuthority() {
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.authority.getDecoded();
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedAuthority() {
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.authority.getEncoded();
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedPath() {
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.path.getEncoded();
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getPath() {
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.path.getDecoded();
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getQuery() {
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.query.getDecoded();
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedQuery() {
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.query.getEncoded();
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getFragment() {
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.fragment.getDecoded();
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String getEncodedFragment() {
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.fragment.getEncoded();
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public List<String> getPathSegments() {
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this.path.getPathSegments();
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private volatile String uriString = NOT_CACHED;
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean cached = (uriString != NOT_CACHED);
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return cached ? uriString
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : (uriString = makeUriString());
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String makeUriString() {
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder builder = new StringBuilder();
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (scheme != null) {
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                builder.append(scheme).append(':');
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            appendSspTo(builder);
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1277a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru            if (!fragment.isEmpty()) {
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                builder.append('#').append(fragment.getEncoded());
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return builder.toString();
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder buildUpon() {
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new Builder()
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .scheme(scheme)
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .authority(authority)
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .path(path)
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .query(query)
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .fragment(fragment);
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Helper class for building or manipulating URI references. Not safe for
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * concurrent use.
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>An absolute hierarchical URI reference follows the pattern:
12994e8620f868e2490782ebb960404140ea9482c91dBen Dodson     * {@code <scheme>://<authority><absolute path>?<query>#<fragment>}
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Relative URI references (which are always hierarchical) follow one
13024e8620f868e2490782ebb960404140ea9482c91dBen Dodson     * of two patterns: {@code <relative or absolute path>?<query>#<fragment>}
13034e8620f868e2490782ebb960404140ea9482c91dBen Dodson     * or {@code //<authority><absolute path>?<query>#<fragment>}
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>An opaque URI follows this pattern:
13064e8620f868e2490782ebb960404140ea9482c91dBen Dodson     * {@code <scheme>:<opaque part>#<fragment>}
13070f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson     *
130858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     * <p>Use {@link Uri#buildUpon()} to obtain a builder representing an existing URI.
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class Builder {
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String scheme;
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part opaquePart;
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part authority;
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PathPart path;
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part query;
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part fragment;
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructs a new Builder.
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder() {}
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the scheme.
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param scheme name or {@code null} if this is a relative Uri
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder scheme(String scheme) {
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.scheme = scheme;
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder opaquePart(Part opaquePart) {
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.opaquePart = opaquePart;
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes and sets the given opaque scheme-specific-part.
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param opaquePart decoded opaque part
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder opaquePart(String opaquePart) {
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return opaquePart(Part.fromDecoded(opaquePart));
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the previously encoded opaque scheme-specific-part.
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param opaquePart encoded opaque part
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder encodedOpaquePart(String opaquePart) {
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return opaquePart(Part.fromEncoded(opaquePart));
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder authority(Part authority) {
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This URI will be hierarchical.
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.opaquePart = null;
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.authority = authority;
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes and sets the authority.
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder authority(String authority) {
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return authority(Part.fromDecoded(authority));
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the previously encoded authority.
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder encodedAuthority(String authority) {
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return authority(Part.fromEncoded(authority));
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder path(PathPart path) {
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This URI will be hierarchical.
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.opaquePart = null;
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.path = path;
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the path. Leaves '/' characters intact but encodes others as
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * necessary.
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>If the path is not null and doesn't start with a '/', and if
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * you specify a scheme and/or authority, the builder will prepend the
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * given path with a '/'.
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder path(String path) {
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path(PathPart.fromDecoded(path));
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the previously encoded path.
14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>If the path is not null and doesn't start with a '/', and if
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * you specify a scheme and/or authority, the builder will prepend the
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * given path with a '/'.
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder encodedPath(String path) {
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path(PathPart.fromEncoded(path));
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes the given segment and appends it to the path.
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder appendPath(String newSegment) {
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path(PathPart.appendDecodedSegment(path, newSegment));
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Appends the given segment to the path.
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder appendEncodedPath(String newSegment) {
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path(PathPart.appendEncodedSegment(path, newSegment));
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder query(Part query) {
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This URI will be hierarchical.
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.opaquePart = null;
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.query = query;
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes and sets the query.
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder query(String query) {
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return query(Part.fromDecoded(query));
14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the previously encoded query.
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder encodedQuery(String query) {
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return query(Part.fromEncoded(query));
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder fragment(Part fragment) {
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.fragment = fragment;
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes and sets the fragment.
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder fragment(String fragment) {
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fragment(Part.fromDecoded(fragment));
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sets the previously encoded fragment.
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder encodedFragment(String fragment) {
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fragment(Part.fromEncoded(fragment));
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Encodes the key and value and then appends the parameter to the
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * query string.
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param key which will be encoded
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param value which will be encoded
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Builder appendQueryParameter(String key, String value) {
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This URI will be hierarchical.
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.opaquePart = null;
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String encodedParameter = encode(key, null) + "="
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + encode(value, null);
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (query == null) {
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                query = Part.fromEncoded(encodedParameter);
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return this;
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String oldQuery = query.getEncoded();
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldQuery == null || oldQuery.length() == 0) {
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                query = Part.fromEncoded(encodedParameter);
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                query = Part.fromEncoded(oldQuery + "&" + encodedParameter);
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return this;
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
149558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson         * Clears the the previously set query.
149658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson         */
149758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        public Builder clearQuery() {
149858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson          return query((Part) null);
149958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        }
150058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
150158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        /**
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructs a Uri with the current attributes.
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @throws UnsupportedOperationException if the URI is opaque and the
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  scheme is null
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Uri build() {
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (opaquePart != null) {
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (this.scheme == null) {
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new UnsupportedOperationException(
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "An opaque URI must have a scheme.");
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new OpaqueUri(scheme, opaquePart, fragment);
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Hierarchical URIs should not return null for getPath().
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PathPart path = this.path;
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (path == null || path == PathPart.NULL) {
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    path = PathPart.EMPTY;
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // If we have a scheme and/or authority, the path must
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // be absolute. Prepend it with a '/' if necessary.
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (hasSchemeOrAuthority()) {
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        path = PathPart.makeAbsolute(path);
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new HierarchicalUri(
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        scheme, authority, path, query, fragment);
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean hasSchemeOrAuthority() {
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return scheme != null
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || (authority != null && authority != Part.NULL);
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return build().toString();
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
154658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     * Returns a set of the unique names of all query parameters. Iterating
154758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     * over the set will return the names in order of their first occurrence.
154858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     *
154958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     * @throws UnsupportedOperationException if this isn't a hierarchical URI
155058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     *
155158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     * @return a set of decoded names
155258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson     */
155358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson    public Set<String> getQueryParameterNames() {
155458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        if (isOpaque()) {
155558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            throw new UnsupportedOperationException(NOT_HIERARCHICAL);
155658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        }
155758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
155858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        String query = getEncodedQuery();
155958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        if (query == null) {
156058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            return Collections.emptySet();
156158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        }
156258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
156358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        Set<String> names = new LinkedHashSet<String>();
156458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        int start = 0;
156558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        do {
156658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int next = query.indexOf('&', start);
156758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int end = (next == -1) ? query.length() : next;
156858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
156958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int separator = query.indexOf('=', start);
157058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (separator > end || separator == -1) {
157158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                separator = end;
157258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            }
157358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
157458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            String name = query.substring(start, separator);
157558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            names.add(decode(name));
157658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
157758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            // Move start to end of name.
157858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            start = end + 1;
157958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        } while (start < query.length());
158058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
158158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        return Collections.unmodifiableSet(names);
158258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson    }
158358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
158458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson    /**
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Searches the query string for parameter values with the given key.
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param key which will be encoded
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws UnsupportedOperationException if this isn't a hierarchical URI
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if key is null
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a list of decoded values
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<String> getQueryParameters(String key) {
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isOpaque()) {
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new UnsupportedOperationException(NOT_HIERARCHICAL);
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
159758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        if (key == null) {
159858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson          throw new NullPointerException("key");
159958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        }
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1601a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru        String query = getEncodedQuery();
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (query == null) {
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Collections.emptyList();
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String encodedKey;
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            encodedKey = URLEncoder.encode(key, DEFAULT_ENCODING);
16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException e) {
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new AssertionError(e);
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<String> values = new ArrayList<String>();
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = 0;
161658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        do {
161758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int nextAmpersand = query.indexOf('&', start);
161858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int end = nextAmpersand != -1 ? nextAmpersand : query.length();
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
162058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int separator = query.indexOf('=', start);
162158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (separator > end || separator == -1) {
162258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                separator = end;
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
162558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (separator - start == encodedKey.length()
162658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                    && query.regionMatches(start, encodedKey, 0, encodedKey.length())) {
162758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                if (separator == end) {
162858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                  values.add("");
162958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                } else {
163058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                  values.add(decode(query.substring(separator + 1, end)));
163158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                }
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
163458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            // Move start to end of name.
163558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (nextAmpersand != -1) {
163658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                start = nextAmpersand + 1;
163758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            } else {
163858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                break;
163958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            }
164058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        } while (true);
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Collections.unmodifiableList(values);
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Searches the query string for the first value with the given key.
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param key which will be encoded
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws UnsupportedOperationException if this isn't a hierarchical URI
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if key is null
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the decoded value or null if no parameter is found
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getQueryParameter(String key) {
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isOpaque()) {
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new UnsupportedOperationException(NOT_HIERARCHICAL);
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
165770ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick        if (key == null) {
1658f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton            throw new NullPointerException("key");
165970ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick        }
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
166170ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick        final String query = getEncodedQuery();
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (query == null) {
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
166670ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick        final String encodedKey = encode(key, null);
166758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        final int length = query.length();
166858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        int start = 0;
166958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        do {
167058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int nextAmpersand = query.indexOf('&', start);
167158a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int end = nextAmpersand != -1 ? nextAmpersand : length;
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
167358a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            int separator = query.indexOf('=', start);
167458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (separator > end || separator == -1) {
167558a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                separator = end;
167670ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick            }
167758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
167858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (separator - start == encodedKey.length()
167958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                    && query.regionMatches(start, encodedKey, 0, encodedKey.length())) {
168058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                if (separator == end) {
16810f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson                    return "";
168258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                } else {
16830f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson                    String encodedValue = query.substring(separator + 1, end);
16840f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson                    return UriCodec.decode(encodedValue, true, Charsets.UTF_8, false);
168570ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick                }
168658a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            }
168758a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson
168858a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            // Move start to end of name.
168958a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson            if (nextAmpersand != -1) {
169058a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                start = nextAmpersand + 1;
1691e41c317348cfe23a78bfd97609c3489c6cc4a786Keith Ito            } else {
169258a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson                break;
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
169458a345936d7e2b66bdeefb492e4f777754792d7eBen Dodson        } while (true);
169570ece8d334485af47edfb5bf3049bef2cf5f4df6Brad Fitzpatrick        return null;
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1698f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton    /**
1699f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * Searches the query string for the first value with the given key and interprets it
1700f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * as a boolean value. "false" and "0" are interpreted as <code>false</code>, everything
1701f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * else is interpreted as <code>true</code>.
1702f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     *
1703f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * @param key which will be decoded
1704f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * @param defaultValue the default value to return if there is no query parameter for key
1705f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     * @return the boolean interpretation of the query parameter key
1706f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton     */
1707f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton    public boolean getBooleanQueryParameter(String key, boolean defaultValue) {
1708f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton        String flag = getQueryParameter(key);
1709f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton        if (flag == null) {
1710f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton            return defaultValue;
1711f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton        }
1712f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton        flag = flag.toLowerCase();
1713f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton        return (!"false".equals(flag) && !"0".equals(flag));
1714f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton    }
1715f0cfe3438aea77b5193d94fb9fa0c8d37972b194Jeff Hamilton
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Identifies a null parcelled Uri. */
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NULL_TYPE_ID = 0;
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads Uris from Parcels.
17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Parcelable.Creator<Uri> CREATOR
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = new Parcelable.Creator<Uri>() {
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Uri createFromParcel(Parcel in) {
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int type = in.readInt();
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (type) {
17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case NULL_TYPE_ID: return null;
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case StringUri.TYPE_ID: return StringUri.readFrom(in);
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case OpaqueUri.TYPE_ID: return OpaqueUri.readFrom(in);
17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case HierarchicalUri.TYPE_ID:
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return HierarchicalUri.readFrom(in);
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17348e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn            throw new IllegalArgumentException("Unknown URI type: " + type);
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Uri[] newArray(int size) {
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new Uri[size];
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Writes a Uri to a Parcel.
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param out parcel to write to
17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param uri to write, can be null
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void writeToParcel(Parcel out, Uri uri) {
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (uri == null) {
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.writeInt(NULL_TYPE_ID);
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uri.writeToParcel(out, 0);
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Encodes characters in the given string as '%'-escaped octets
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * all other characters.
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param s string to encode
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return an encoded version of s suitable for use as a URI component,
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  or null if s is null
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String encode(String s) {
17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return encode(s, null);
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Encodes characters in the given string as '%'-escaped octets
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers
17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * all other characters with the exception of those specified in the
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * allow argument.
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param s string to encode
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allow set of additional characters to allow in the encoded form,
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  null if no characters should be skipped
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return an encoded version of s suitable for use as a URI component,
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  or null if s is null
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String encode(String s, String allow) {
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s == null) {
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Lazily-initialized buffers.
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder encoded = null;
17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int oldLength = s.length();
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This loop alternates between copying over allowed characters and
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // encoding in chunks. This results in fewer method calls and
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // allocations than encoding one character at a time.
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int current = 0;
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (current < oldLength) {
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Start in "copying" mode where we copy over allowed chars.
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find the next character which needs to be encoded.
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int nextToEncode = current;
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (nextToEncode < oldLength
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && isAllowed(s.charAt(nextToEncode), allow)) {
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                nextToEncode++;
18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If there's nothing more to encode...
18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextToEncode == oldLength) {
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (current == 0) {
18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We didn't need to encode anything!
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return s;
18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Presumably, we've already done some encoding.
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    encoded.append(s, current, oldLength);
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return encoded.toString();
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encoded == null) {
18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                encoded = new StringBuilder();
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextToEncode > current) {
18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Append allowed characters leading up to this point.
18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                encoded.append(s, current, nextToEncode);
18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // assert nextToEncode == current
18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Switch to "encoding" mode.
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Find the next allowed character.
18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            current = nextToEncode;
18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int nextAllowed = current + 1;
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (nextAllowed < oldLength
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && !isAllowed(s.charAt(nextAllowed), allow)) {
18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                nextAllowed++;
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Convert the substring to bytes and encode the bytes as
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // '%'-escaped octets.
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String toEncode = s.substring(current, nextAllowed);
18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                byte[] bytes = toEncode.getBytes(DEFAULT_ENCODING);
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int bytesLength = bytes.length;
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < bytesLength; i++) {
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    encoded.append('%');
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    encoded.append(HEX_DIGITS[(bytes[i] & 0xf0) >> 4]);
18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    encoded.append(HEX_DIGITS[bytes[i] & 0xf]);
18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (UnsupportedEncodingException e) {
18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new AssertionError(e);
18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            current = nextAllowed;
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Encoded could still be null at this point if s is empty.
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return encoded == null ? s : encoded.toString();
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the given character is allowed.
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param c character to check
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allow characters to allow
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the character is allowed or false if it should be
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  encoded
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isAllowed(char c, String allow) {
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= 'A' && c <= 'Z')
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || (c >= 'a' && c <= 'z')
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || (c >= '0' && c <= '9')
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || "_-!.~'()*".indexOf(c) != NOT_FOUND
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || (allow != null && allow.indexOf(c) != NOT_FOUND);
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Decodes '%'-escaped octets in the given string using the UTF-8 scheme.
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Replaces invalid octets with the unicode replacement character
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ("\\uFFFD").
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param s encoded string to decode
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the given string with escaped octets decoded, or null if
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  s is null
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String decode(String s) {
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s == null) {
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18930f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson        return UriCodec.decode(s, false, Charsets.UTF_8, false);
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Support for part implementations.
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static abstract class AbstractPart {
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Enum which indicates which representation of a given part we have.
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static class Representation {
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            static final int BOTH = 0;
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            static final int ENCODED = 1;
19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            static final int DECODED = 2;
19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        volatile String encoded;
19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        volatile String decoded;
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AbstractPart(String encoded, String decoded) {
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.encoded = encoded;
19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.decoded = decoded;
19169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        abstract String getEncoded();
19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String getDecoded() {
19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasDecoded = decoded != NOT_CACHED;
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return hasDecoded ? decoded : (decoded = decode(encoded));
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final void writeTo(Parcel parcel) {
19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasEncoded = encoded != NOT_CACHED;
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasDecoded = decoded != NOT_CACHED;
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (hasEncoded && hasDecoded) {
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeInt(Representation.BOTH);
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeString(encoded);
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeString(decoded);
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (hasEncoded) {
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeInt(Representation.ENCODED);
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeString(encoded);
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (hasDecoded) {
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeInt(Representation.DECODED);
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parcel.writeString(decoded);
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
19448e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn                throw new IllegalArgumentException("Neither encoded nor decoded");
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Immutable wrapper of encoded and decoded versions of a URI part. Lazily
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * creates the encoded or decoded version from the other.
19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class Part extends AbstractPart {
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** A part with null values. */
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final Part NULL = new EmptyPart(null);
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** A part with empty strings for values. */
19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final Part EMPTY = new EmptyPart("");
19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Part(String encoded, String decoded) {
19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(encoded, decoded);
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isEmpty() {
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String getEncoded() {
19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasEncoded = encoded != NOT_CACHED;
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return hasEncoded ? encoded : (encoded = encode(decoded));
19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Part readFrom(Parcel parcel) {
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int representation = parcel.readInt();
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (representation) {
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.BOTH:
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return from(parcel.readString(), parcel.readString());
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.ENCODED:
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return fromEncoded(parcel.readString());
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.DECODED:
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return fromDecoded(parcel.readString());
19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default:
19858e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn                    throw new IllegalArgumentException("Unknown representation: "
19868e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn                            + representation);
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Returns given part or {@link #NULL} if the given part is null.
19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Part nonNull(Part part) {
19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return part == null ? NULL : part;
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a part from the encoded string.
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param encoded part string
20019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Part fromEncoded(String encoded) {
20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return from(encoded, NOT_CACHED);
20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a part from the decoded string.
20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param decoded part string
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Part fromDecoded(String decoded) {
20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return from(NOT_CACHED, decoded);
20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a part from the encoded and decoded strings.
20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param encoded part string
20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param decoded part string
20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static Part from(String encoded, String decoded) {
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We have to check both encoded and decoded in case one is
20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // NOT_CACHED.
20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encoded == null) {
20269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return NULL;
20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encoded.length() == 0) {
20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return EMPTY;
20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (decoded == null) {
20339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return NULL;
20349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (decoded .length() == 0) {
20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return EMPTY;
20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new Part(encoded, decoded);
20409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static class EmptyPart extends Part {
20439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public EmptyPart(String value) {
20449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                super(value, value);
20459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
20489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isEmpty() {
20499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
20509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Immutable wrapper of encoded and decoded versions of a path part. Lazily
20569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * creates the encoded or decoded version from the other.
20579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class PathPart extends AbstractPart {
20599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** A part with null values. */
20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final PathPart NULL = new PathPart(null, null);
20629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** A part with empty strings for values. */
20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static final PathPart EMPTY = new PathPart("", "");
20659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PathPart(String encoded, String decoded) {
20679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(encoded, decoded);
20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String getEncoded() {
20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasEncoded = encoded != NOT_CACHED;
20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Don't encode '/'.
20759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return hasEncoded ? encoded : (encoded = encode(decoded, "/"));
20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Cached path segments. This doesn't need to be volatile--we don't
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * care if other threads see the result.
20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PathSegments pathSegments;
20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Gets the individual path segments. Parses them if necessary.
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return parsed path segments or null if this isn't a hierarchical
20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  URI
20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PathSegments getPathSegments() {
20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pathSegments != null) {
20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return pathSegments;
20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String path = getEncoded();
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (path == null) {
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return pathSegments = PathSegments.EMPTY;
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PathSegmentsBuilder segmentBuilder = new PathSegmentsBuilder();
21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int previous = 0;
21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int current;
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((current = path.indexOf('/', previous)) > -1) {
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This check keeps us from adding a segment if the path starts
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // '/' and an empty segment for "//".
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (previous < current) {
21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String decodedSegment
21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            = decode(path.substring(previous, current));
21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    segmentBuilder.add(decodedSegment);
21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                previous = current + 1;
21139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Add in the final path segment.
21169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (previous < path.length()) {
21179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segmentBuilder.add(decode(path.substring(previous)));
21189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pathSegments = segmentBuilder.build();
21219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart appendEncodedSegment(PathPart oldPart,
21249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String newSegment) {
21259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If there is no old path, should we make the new path relative
21269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // or absolute? I pick absolute.
21279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldPart == null) {
21299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // No old path.
21309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return fromEncoded("/" + newSegment);
21319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String oldPath = oldPart.getEncoded();
21349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldPath == null) {
21369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldPath = "";
21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldPathLength = oldPath.length();
21409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String newPath;
21419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldPathLength == 0) {
21429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // No old path.
21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newPath = "/" + newSegment;
21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (oldPath.charAt(oldPathLength - 1) == '/') {
21459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newPath = oldPath + newSegment;
21469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
21479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newPath = oldPath + "/" + newSegment;
21489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return fromEncoded(newPath);
21519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart appendDecodedSegment(PathPart oldPart, String decoded) {
21549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String encoded = encode(decoded);
21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: Should we reuse old PathSegments? Probably not.
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return appendEncodedSegment(oldPart, encoded);
21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart readFrom(Parcel parcel) {
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int representation = parcel.readInt();
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (representation) {
21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.BOTH:
21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return from(parcel.readString(), parcel.readString());
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.ENCODED:
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return fromEncoded(parcel.readString());
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case Representation.DECODED:
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return fromDecoded(parcel.readString());
21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default:
21708e8d65ff5fdef12c6af3d003dfef19aadc39bea9Dianne Hackborn                    throw new IllegalArgumentException("Bad representation: " + representation);
21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a path from the encoded string.
21769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param encoded part string
21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart fromEncoded(String encoded) {
21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return from(encoded, NOT_CACHED);
21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a path from the decoded string.
21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param decoded part string
21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart fromDecoded(String decoded) {
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return from(NOT_CACHED, decoded);
21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Creates a path from the encoded and decoded strings.
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param encoded part string
21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param decoded part string
21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart from(String encoded, String decoded) {
21999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encoded == null) {
22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return NULL;
22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (encoded.length() == 0) {
22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return EMPTY;
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new PathPart(encoded, decoded);
22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
22119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Prepends path values with "/" if they're present, not empty, and
22129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * they don't already start with "/".
22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PathPart makeAbsolute(PathPart oldPart) {
22159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
22169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean encodedCached = oldPart.encoded != NOT_CACHED;
22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We don't care which version we use, and we don't want to force
22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // unneccessary encoding/decoding.
22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String oldPath = encodedCached ? oldPart.encoded : oldPart.decoded;
22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldPath == null || oldPath.length() == 0
22239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || oldPath.startsWith("/")) {
22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return oldPart;
22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Prepend encoded string if present.
22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String newEncoded = encodedCached
22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? "/" + oldPart.encoded : NOT_CACHED;
22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Prepend decoded string if present.
22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @SuppressWarnings("StringEquality")
22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean decodedCached = oldPart.decoded != NOT_CACHED;
22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String newDecoded = decodedCached
22359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? "/" + oldPart.decoded
22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : NOT_CACHED;
22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new PathPart(newEncoded, newDecoded);
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new Uri by appending an already-encoded path segment to a
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * base Uri.
22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param baseUri Uri to append path segment to
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pathSegment encoded path segment to append
22480f28af209ac877091f4a096f7553f02a0b401596Jesse Wilson     * @return a new Uri based on baseUri with the given segment appended to
22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  the path
22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if baseUri is null
22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
22529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Builder builder = baseUri.buildUpon();
22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        builder = builder.appendEncodedPath(pathSegment);
22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return builder.build();
22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2258