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