Merge "Polish new IME API for L: CursorAnchorInfo"
diff --git a/api/current.txt b/api/current.txt
index 0e793ae..8642eee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26589,28 +26589,6 @@
 
 package android.speech.tts {
 
-  public final class Markup implements android.os.Parcelable {
-    ctor public Markup();
-    ctor public Markup(java.lang.String);
-    ctor public Markup(android.speech.tts.Markup);
-    method public android.speech.tts.Markup addNestedMarkup(android.speech.tts.Markup);
-    method public int describeContents();
-    method public android.speech.tts.Markup getNestedMarkup(int);
-    method public java.util.List<android.speech.tts.Markup> getNestedMarkups();
-    method public java.lang.String getParameter(java.lang.String);
-    method public java.lang.String getPlainText();
-    method public java.lang.String getType();
-    method public static android.speech.tts.Markup markupFromString(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public int nestedMarkupSize();
-    method public int parametersSize();
-    method public boolean removeNestedMarkup(android.speech.tts.Markup);
-    method public void removeParameter(java.lang.String);
-    method public android.speech.tts.Markup setParameter(java.lang.String, java.lang.String);
-    method public void setPlainText(java.lang.String);
-    method public void setType(java.lang.String);
-    method public void writeToParcel(android.os.Parcel, int);
-  }
-
   public abstract interface SynthesisCallback {
     method public abstract int audioAvailable(byte[], int, int);
     method public abstract int done();
@@ -26760,85 +26738,6 @@
     method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
   }
 
-  public class Utterance {
-    ctor public Utterance();
-    method public android.speech.tts.Utterance append(android.speech.tts.Utterance.AbstractTts<? extends android.speech.tts.Utterance.AbstractTts<?>>);
-    method public android.speech.tts.Utterance append(java.lang.String);
-    method public android.speech.tts.Utterance append(int);
-    method public android.speech.tts.Markup createMarkup();
-    method public android.speech.tts.Utterance.AbstractTts<? extends android.speech.tts.Utterance.AbstractTts<?>> get(int);
-    method public android.speech.tts.Utterance setNoWarningOnFallback(boolean);
-    method public int size();
-    method public static android.speech.tts.Utterance utteranceFromString(java.lang.String) throws java.lang.IllegalArgumentException;
-    field public static final int ANIMACY_ANIMATE = 1; // 0x1
-    field public static final int ANIMACY_INANIMATE = 2; // 0x2
-    field public static final int ANIMACY_UNKNOWN = 0; // 0x0
-    field public static final int CASE_ABLATIVE = 4; // 0x4
-    field public static final int CASE_ACCUSATIVE = 2; // 0x2
-    field public static final int CASE_DATIVE = 3; // 0x3
-    field public static final int CASE_GENITIVE = 5; // 0x5
-    field public static final int CASE_INSTRUMENTAL = 8; // 0x8
-    field public static final int CASE_LOCATIVE = 7; // 0x7
-    field public static final int CASE_NOMINATIVE = 1; // 0x1
-    field public static final int CASE_UNKNOWN = 0; // 0x0
-    field public static final int CASE_VOCATIVE = 6; // 0x6
-    field public static final int GENDER_FEMALE = 3; // 0x3
-    field public static final int GENDER_MALE = 2; // 0x2
-    field public static final int GENDER_NEUTRAL = 1; // 0x1
-    field public static final int GENDER_UNKNOWN = 0; // 0x0
-    field public static final java.lang.String KEY_NO_WARNING_ON_FALLBACK = "no_warning_on_fallback";
-    field public static final int MULTIPLICITY_DUAL = 2; // 0x2
-    field public static final int MULTIPLICITY_PLURAL = 3; // 0x3
-    field public static final int MULTIPLICITY_SINGLE = 1; // 0x1
-    field public static final int MULTIPLICITY_UNKNOWN = 0; // 0x0
-    field public static final java.lang.String TYPE_UTTERANCE = "utterance";
-  }
-
-  public static abstract class Utterance.AbstractTts {
-    ctor protected Utterance.AbstractTts();
-    ctor protected Utterance.AbstractTts(android.speech.tts.Markup);
-    method public java.lang.String generatePlainText();
-    method public android.speech.tts.Markup getMarkup();
-    method protected java.lang.String getParameter(java.lang.String);
-    method public java.lang.String getPlainText();
-    method public java.lang.String getType();
-    method protected C removeParameter(java.lang.String);
-    method protected C setParameter(java.lang.String, java.lang.String);
-    method public C setPlainText(java.lang.String);
-    field protected android.speech.tts.Markup mMarkup;
-  }
-
-  public static abstract class Utterance.AbstractTtsSemioticClass extends android.speech.tts.Utterance.AbstractTts {
-    ctor protected Utterance.AbstractTtsSemioticClass();
-    ctor protected Utterance.AbstractTtsSemioticClass(android.speech.tts.Markup);
-    method public int getAnimacy();
-    method public int getCase();
-    method public int getGender();
-    method public int getMultiplicity();
-    method public C setAnimacy(int);
-    method public C setCase(int);
-    method public C setGender(int);
-    method public C setMultiplicity(int);
-  }
-
-  public static class Utterance.TtsCardinal extends android.speech.tts.Utterance.AbstractTtsSemioticClass {
-    ctor public Utterance.TtsCardinal();
-    ctor public Utterance.TtsCardinal(int);
-    ctor public Utterance.TtsCardinal(java.lang.String);
-    method public java.lang.String getInteger();
-    method public android.speech.tts.Utterance.TtsCardinal setInteger(int);
-    method public android.speech.tts.Utterance.TtsCardinal setInteger(java.lang.String);
-    field protected static final java.lang.String TYPE_CARDINAL = "cardinal";
-  }
-
-  public static class Utterance.TtsText extends android.speech.tts.Utterance.AbstractTtsSemioticClass {
-    ctor public Utterance.TtsText();
-    ctor public Utterance.TtsText(java.lang.String);
-    method public java.lang.String getText();
-    method public android.speech.tts.Utterance.TtsText setText(java.lang.String);
-    field protected static final java.lang.String TYPE_TEXT = "text";
-  }
-
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
     method public abstract void onDone(java.lang.String);
@@ -27634,13 +27533,13 @@
     ctor protected Connection();
     method public final boolean getAudioModeIsVoip();
     method public final android.telecomm.CallAudioState getCallAudioState();
+    method public final int getCallCapabilities();
     method public final java.util.List<android.telecomm.Connection> getChildConnections();
     method public final int getFeatures();
     method public final android.net.Uri getHandle();
     method public final android.telecomm.Connection getParentConnection();
     method public final int getState();
     method public final android.telecomm.StatusHints getStatusHints();
-    method public final boolean isConferenceCapable();
     method public final boolean isConferenceConnection();
     method public final boolean isRequestingRingback();
     method protected void onAbort();
@@ -27659,13 +27558,13 @@
     method protected void onUnhold();
     method public final void setActive();
     method public final void setAudioModeIsVoip(boolean);
+    method public final void setCallCapabilities(int);
     method public final void setCallVideoProvider(android.telecomm.CallVideoProvider);
     method public final void setDestroyed();
     method public final void setDialing();
     method public final void setDisconnected(int, java.lang.String);
     method public final void setFeatures(int);
     method public final void setHandle(android.net.Uri);
-    method public final void setIsConferenceCapable(boolean);
     method public final void setOnHold();
     method public final void setParentConnection(android.telecomm.Connection);
     method public final void setPostDialWait(java.lang.String);
@@ -27822,6 +27721,7 @@
     method public void answer();
     method public void disconnect();
     method public boolean getAudioModeIsVoip();
+    method public int getCallCapabilities();
     method public int getDisconnectCause();
     method public java.lang.String getDisconnectMessage();
     method public int getFeatures();
@@ -27838,6 +27738,7 @@
   }
 
   public static abstract interface RemoteConnection.Listener {
+    method public abstract void onCallCapabilitiesChanged(android.telecomm.RemoteConnection, int);
     method public abstract void onDestroyed(android.telecomm.RemoteConnection);
     method public abstract void onDisconnected(android.telecomm.RemoteConnection, int, java.lang.String);
     method public abstract void onFeaturesChanged(android.telecomm.RemoteConnection, int);
diff --git a/core/java/android/speech/tts/Markup.java b/core/java/android/speech/tts/Markup.java
deleted file mode 100644
index c886e5d..0000000
--- a/core/java/android/speech/tts/Markup.java
+++ /dev/null
@@ -1,537 +0,0 @@
-package android.speech.tts;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A class that provides markup to a synthesis request to control aspects of speech.
- * <p>
- * Markup itself is a feature agnostic data format; the {@link Utterance} class defines the currently
- * available set of features and should be used to construct instances of the Markup class.
- * </p>
- * <p>
- * A marked up sentence is a tree. Each node has a type, an optional plain text, a set of
- * parameters, and a list of children.
- * The <b>type</b> defines what it contains, e.g. "text", "date", "measure", etc. A Markup node
- * can be either a part of sentence (often a leaf node), or node altering some property of its
- * children (node with children). The top level node has to be of type "utterance" and its children
- * are synthesized in order.
- * The <b>plain text</b> is optional except for the top level node. If the synthesis engine does not
- * support Markup at all, it should use the plain text of the top level node. If an engine does not
- * recognize or support a node type, it will try to use the plain text of that node if provided. If
- * the plain text is null, it will synthesize its children in order.
- * <b>Parameters</b> are key-value pairs specific to each node type. In case of a date node the
- * parameters may be for example "month: 7" and "day: 10".
- * The <b>nested markups</b> are children and can for example be used to nest semiotic classes (a
- * measure may have a node of type "decimal" as its child) or to modify some property of its
- * children. See "plain text" on how they are processed if the parent of the children is unknown to
- * the engine.
- * <p>
- */
-public final class Markup implements Parcelable {
-
-    private String mType;
-    private String mPlainText;
-
-    private Bundle mParameters = new Bundle();
-    private List<Markup> mNestedMarkups = new ArrayList<Markup>();
-
-    private static final String TYPE = "type";
-    private static final String PLAIN_TEXT = "plain_text";
-    private static final String MARKUP = "markup";
-
-    private static final String IDENTIFIER_REGEX = "([0-9a-z_]+)";
-    private static final Pattern legalIdentifierPattern = Pattern.compile(IDENTIFIER_REGEX);
-
-    /**
-     * Constructs an empty markup.
-     */
-    public Markup() {}
-
-    /**
-     * Constructs a markup of the given type.
-     */
-    public Markup(String type) {
-        setType(type);
-    }
-
-    /**
-     * Returns the type of this node; can be null.
-     */
-    public String getType() {
-        return mType;
-    }
-
-    /**
-     * Sets the type of this node. can be null. May only contain [0-9a-z_].
-     */
-    public void setType(String type) {
-        if (type != null) {
-            Matcher matcher = legalIdentifierPattern.matcher(type);
-            if (!matcher.matches()) {
-                throw new IllegalArgumentException("Type cannot be empty and may only contain " +
-                                                   "0-9, a-z and underscores.");
-            }
-        }
-        mType = type;
-    }
-
-    /**
-     * Returns this node's plain text; can be null.
-     */
-    public String getPlainText() {
-        return mPlainText;
-    }
-
-    /**
-     * Sets this nodes's plain text; can be null.
-     */
-    public void setPlainText(String plainText) {
-        mPlainText = plainText;
-    }
-
-    /**
-     * Adds or modifies a parameter.
-     * @param key The key; may only contain [0-9a-z_] and cannot be "type" or "plain_text".
-     * @param value The value.
-     * @throws An {@link IllegalArgumentException} if the key is null or empty.
-     * @return this
-     */
-    public Markup setParameter(String key, String value) {
-        if (key == null || key.isEmpty()) {
-            throw new IllegalArgumentException("Key cannot be null or empty.");
-        }
-        if (key.equals("type")) {
-            throw new IllegalArgumentException("Key cannot be \"type\".");
-        }
-        if (key.equals("plain_text")) {
-            throw new IllegalArgumentException("Key cannot be \"plain_text\".");
-        }
-        Matcher matcher = legalIdentifierPattern.matcher(key);
-        if (!matcher.matches()) {
-            throw new IllegalArgumentException("Key may only contain 0-9, a-z and underscores.");
-        }
-
-        if (value != null) {
-            mParameters.putString(key, value);
-        } else {
-            removeParameter(key);
-        }
-        return this;
-    }
-
-    /**
-     * Removes the parameter with the given key
-     */
-    public void removeParameter(String key) {
-        mParameters.remove(key);
-    }
-
-    /**
-     * Returns the value of the parameter.
-     * @param key The parameter key.
-     * @return The value of the parameter or null if the parameter is not set.
-     */
-    public String getParameter(String key) {
-        return mParameters.getString(key);
-    }
-
-    /**
-     * Returns the number of parameters that have been set.
-     */
-    public int parametersSize() {
-        return mParameters.size();
-    }
-
-    /**
-     * Appends a child to the list of children
-     * @param markup The child.
-     * @return This instance.
-     * @throws {@link IllegalArgumentException} if markup is null.
-     */
-    public Markup addNestedMarkup(Markup markup) {
-        if (markup == null) {
-            throw new IllegalArgumentException("Nested markup cannot be null");
-        }
-        mNestedMarkups.add(markup);
-        return this;
-    }
-
-    /**
-     * Removes the given node from its children.
-     * @param markup The child to remove.
-     * @return True if this instance was modified by this operation, false otherwise.
-     */
-    public boolean removeNestedMarkup(Markup markup) {
-        return mNestedMarkups.remove(markup);
-    }
-
-    /**
-     * Returns the index'th child.
-     * @param i The index of the child.
-     * @return The child.
-     * @throws {@link IndexOutOfBoundsException} if i < 0 or i >= nestedMarkupSize()
-     */
-    public Markup getNestedMarkup(int i) {
-        return mNestedMarkups.get(i);
-    }
-
-
-    /**
-     * Returns the number of children.
-     */
-    public int nestedMarkupSize() {
-        return mNestedMarkups.size();
-    }
-
-    /**
-     * Returns a string representation of this Markup instance. Can be deserialized back to a Markup
-     * instance with markupFromString().
-     */
-    public String toString() {
-        StringBuilder out = new StringBuilder();
-        if (mType != null) {
-            out.append(TYPE + ": \"" + mType + "\"");
-        }
-        if (mPlainText != null) {
-            out.append(out.length() > 0 ? " " : "");
-            out.append(PLAIN_TEXT + ": \"" + escapeQuotedString(mPlainText) + "\"");
-        }
-        // Sort the parameters alphabetically by key so we have a stable output.
-        SortedMap<String, String> sortedMap = new TreeMap<String, String>();
-        for (String key : mParameters.keySet()) {
-            sortedMap.put(key, mParameters.getString(key));
-        }
-        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
-            out.append(out.length() > 0 ? " " : "");
-            out.append(entry.getKey() + ": \"" + escapeQuotedString(entry.getValue()) + "\"");
-        }
-        for (Markup m : mNestedMarkups) {
-            out.append(out.length() > 0 ? " " : "");
-            String nestedStr = m.toString();
-            if (nestedStr.isEmpty()) {
-                out.append(MARKUP + " {}");
-            } else {
-                out.append(MARKUP + " { " + m.toString() + " }");
-            }
-        }
-        return out.toString();
-    }
-
-    /**
-     * Escapes backslashes and double quotes in the plain text and parameter values before this
-     * instance is written to a string.
-     * @param str The string to escape.
-     * @return The escaped string.
-     */
-    private static String escapeQuotedString(String str) {
-        StringBuilder out = new StringBuilder();
-        for (int i = 0; i < str.length(); i++) {
-            char c = str.charAt(i);
-            if (c == '"') {
-                out.append("\\\"");
-            } else if (str.charAt(i) == '\\') {
-                out.append("\\\\");
-            } else {
-                out.append(c);
-            }
-        }
-        return out.toString();
-    }
-
-    /**
-     * The reverse of the escape method, returning plain text and parameter values to their original
-     * form.
-     * @param str An escaped string.
-     * @return The unescaped string.
-     */
-    private static String unescapeQuotedString(String str) {
-        StringBuilder out = new StringBuilder();
-        for (int i = 0; i < str.length(); i++) {
-            char c = str.charAt(i);
-            if (c == '\\') {
-                i++;
-                if (i >= str.length()) {
-                    throw new IllegalArgumentException("Unterminated escape sequence in string: " +
-                                                       str);
-                }
-                c = str.charAt(i);
-                if (c == '\\') {
-                    out.append("\\");
-                } else if (c == '"') {
-                    out.append("\"");
-                } else {
-                    throw new IllegalArgumentException("Unsupported escape sequence: \\" + c +
-                                                       " in string " + str);
-                }
-            } else {
-                out.append(c);
-            }
-        }
-        return out.toString();
-    }
-
-    /**
-     * Returns true if the given string consists only of whitespace.
-     * @param str The string to check.
-     * @return True if the given string consists only of whitespace.
-     */
-    private static boolean isWhitespace(String str) {
-        return Pattern.matches("\\s*", str);
-    }
-
-    /**
-     * Parses the given string, and overrides the values of this instance with those contained
-     * in the given string.
-     * @param str The string to parse; can have superfluous whitespace.
-     * @return An empty string on success, else the remainder of the string that could not be
-     *     parsed.
-     */
-    private String fromReadableString(String str) {
-        while (!isWhitespace(str)) {
-            String newStr = matchValue(str);
-            if (newStr == null) {
-                newStr = matchMarkup(str);
-
-                if (newStr == null) {
-                    return str;
-                }
-            }
-            str = newStr;
-        }
-        return "";
-    }
-
-    // Matches: key : "value"
-    // where key is an identifier and value can contain escaped quotes
-    // there may be superflouous whitespace
-    // The value string may contain quotes and backslashes.
-    private static final String OPTIONAL_WHITESPACE = "\\s*";
-    private static final String VALUE_REGEX = "((\\\\.|[^\\\"])*)";
-    private static final String KEY_VALUE_REGEX =
-            "\\A" + OPTIONAL_WHITESPACE +                                         // start of string
-            IDENTIFIER_REGEX + OPTIONAL_WHITESPACE + ":" + OPTIONAL_WHITESPACE +  // key:
-            "\"" + VALUE_REGEX + "\"";                                            // "value"
-    private static final Pattern KEY_VALUE_PATTERN = Pattern.compile(KEY_VALUE_REGEX);
-
-    /**
-     * Tries to match a key-value pair at the start of the string. If found, add that as a parameter
-     * of this instance.
-     * @param str The string to parse.
-     * @return The remainder of the string without the parsed key-value pair on success, else null.
-     */
-    private String matchValue(String str) {
-        // Matches: key: "value"
-        Matcher matcher = KEY_VALUE_PATTERN.matcher(str);
-        if (!matcher.find()) {
-            return null;
-        }
-        String key = matcher.group(1);
-        String value = matcher.group(2);
-
-        if (key == null || value == null) {
-            return null;
-        }
-        String unescapedValue = unescapeQuotedString(value);
-        if (key.equals(TYPE)) {
-            this.mType = unescapedValue;
-        } else if (key.equals(PLAIN_TEXT)) {
-            this.mPlainText = unescapedValue;
-        } else {
-            setParameter(key, unescapedValue);
-        }
-
-        return str.substring(matcher.group(0).length());
-    }
-
-    // matches 'markup {'
-    private static final Pattern OPEN_MARKUP_PATTERN =
-            Pattern.compile("\\A" + OPTIONAL_WHITESPACE + MARKUP + OPTIONAL_WHITESPACE + "\\{");
-    // matches '}'
-    private static final Pattern CLOSE_MARKUP_PATTERN =
-            Pattern.compile("\\A" + OPTIONAL_WHITESPACE + "\\}");
-
-    /**
-     * Tries to parse a Markup specification from the start of the string. If so, add that markup to
-     * the list of nested Markup's of this instance.
-     * @param str The string to parse.
-     * @return The remainder of the string without the parsed Markup on success, else null.
-     */
-    private String matchMarkup(String str) {
-        // find and strip "markup {"
-        Matcher matcher = OPEN_MARKUP_PATTERN.matcher(str);
-
-        if (!matcher.find()) {
-            return null;
-        }
-        String strRemainder = str.substring(matcher.group(0).length());
-        // parse and strip markup contents
-        Markup nestedMarkup = new Markup();
-        strRemainder = nestedMarkup.fromReadableString(strRemainder);
-
-        // find and strip "}"
-        Matcher matcherClose = CLOSE_MARKUP_PATTERN.matcher(strRemainder);
-        if (!matcherClose.find()) {
-            return null;
-        }
-        strRemainder = strRemainder.substring(matcherClose.group(0).length());
-
-        // Everything parsed, add markup
-        this.addNestedMarkup(nestedMarkup);
-
-        // Return remainder
-        return strRemainder;
-    }
-
-    /**
-     * Returns a Markup instance from the string representation generated by toString().
-     * @param string The string representation generated by toString().
-     * @return The new Markup instance.
-     * @throws {@link IllegalArgumentException} if the input cannot be correctly parsed.
-     */
-    public static Markup markupFromString(String string) throws IllegalArgumentException {
-        Markup m = new Markup();
-        if (m.fromReadableString(string).isEmpty()) {
-            return m;
-        } else {
-            throw new IllegalArgumentException("Cannot parse input to Markup");
-        }
-    }
-
-    /**
-     * Compares the specified object with this Markup for equality.
-     * @return True if the given object is a Markup instance with the same type, plain text,
-     * parameters and the nested markups are also equal to each other and in the same order.
-     */
-    @Override
-    public boolean equals(Object o) {
-        if ( this == o ) return true;
-        if ( !(o instanceof Markup) ) return false;
-        Markup m = (Markup) o;
-
-        if (nestedMarkupSize() != this.nestedMarkupSize()) {
-            return false;
-        }
-
-        if (!(mType == null ? m.mType == null : mType.equals(m.mType))) {
-            return false;
-        }
-        if (!(mPlainText == null ? m.mPlainText == null : mPlainText.equals(m.mPlainText))) {
-            return false;
-        }
-        if (!equalBundles(mParameters, m.mParameters)) {
-            return false;
-        }
-
-        for (int i = 0; i < this.nestedMarkupSize(); i++) {
-            if (!mNestedMarkups.get(i).equals(m.mNestedMarkups.get(i))) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Checks if two bundles are equal to each other. Used by equals(o).
-     */
-    private boolean equalBundles(Bundle one, Bundle two) {
-        if (one == null || two == null) {
-            return false;
-        }
-
-        if(one.size() != two.size()) {
-            return false;
-        }
-
-        Set<String> valuesOne = one.keySet();
-        for(String key : valuesOne) {
-            Object valueOne = one.get(key);
-            Object valueTwo = two.get(key);
-            if (valueOne instanceof Bundle && valueTwo instanceof Bundle &&
-                !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) {
-                return false;
-            } else if (valueOne == null) {
-                if (valueTwo != null || !two.containsKey(key)) {
-                    return false;
-                }
-            } else if(!valueOne.equals(valueTwo)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Returns an unmodifiable list of the children.
-     * @return An unmodifiable list of children that throws an {@link UnsupportedOperationException}
-     *     if an attempt is made to modify it
-     */
-    public List<Markup> getNestedMarkups() {
-        return Collections.unmodifiableList(mNestedMarkups);
-    }
-
-    /**
-     * @hide
-     */
-    public Markup(Parcel in) {
-        mType = in.readString();
-        mPlainText = in.readString();
-        mParameters = in.readBundle();
-        in.readList(mNestedMarkups, Markup.class.getClassLoader());
-    }
-
-    /**
-     * Creates a deep copy of the given markup.
-     */
-    public Markup(Markup markup) {
-        mType = markup.mType;
-        mPlainText = markup.mPlainText;
-        mParameters = markup.mParameters;
-        for (Markup nested : markup.getNestedMarkups()) {
-            addNestedMarkup(new Markup(nested));
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * @hide
-     */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mType);
-        dest.writeString(mPlainText);
-        dest.writeBundle(mParameters);
-        dest.writeList(mNestedMarkups);
-    }
-
-    /**
-     * @hide
-     */
-    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
-        public Markup createFromParcel(Parcel in) {
-            return new Markup(in);
-        }
-
-        public Markup[] newArray(int size) {
-            return new Markup[size];
-        }
-    };
-}
-
diff --git a/core/java/android/speech/tts/Utterance.java b/core/java/android/speech/tts/Utterance.java
deleted file mode 100644
index 0a29283..0000000
--- a/core/java/android/speech/tts/Utterance.java
+++ /dev/null
@@ -1,595 +0,0 @@
-package android.speech.tts;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class acts as a builder for {@link Markup} instances.
- * <p>
- * Each Utterance consists of a list of the semiotic classes ({@link Utterance.TtsCardinal} and
- * {@link Utterance.TtsText}).
- * <p>Each semiotic class can be supplied with morphosyntactic features
- * (gender, animacy, multiplicity and case), it is up to the synthesis engine to use this
- * information during synthesis.
- * Examples where morphosyntactic features matter:
- * <ul>
- * <li>In French, the number one is verbalized differently based on the gender of the noun
- * it modifies. "un homme" (one man) versus "une femme" (one woman).
- * <li>In German the grammatical case (accusative, locative, etc) needs to be included to be
- * verbalize correctly. In German you'd have the sentence "Sie haben 1 kilometer vor Ihnen" (You
- * have 1 kilometer ahead of you), "1" in this case needs to become inflected to the accusative
- * form ("einen") instead of the nominative form "ein".
- * </p>
- * <p>
- * Utterance usage example:
- * Markup m1 = new Utterance().append("The Eiffel Tower is")
- *                            .append(new TtsCardinal(324))
- *                            .append("meters tall.");
- * Markup m2 = new Utterance().append("Sie haben")
- *                            .append(new TtsCardinal(1).setGender(Utterance.GENDER_MALE)
- *                            .append("Tag frei.");
- * </p>
- */
-public class Utterance {
-
-    /***
-     * Toplevel type of markup representation.
-     */
-    public static final String TYPE_UTTERANCE = "utterance";
-    /***
-     * The no_warning_on_fallback parameter can be set to "false" or "true", true indicating that
-     * no warning will be given when the synthesizer does not support Markup. This is used when
-     * the user only provides a string to the API instead of a markup.
-     */
-    public static final String KEY_NO_WARNING_ON_FALLBACK = "no_warning_on_fallback";
-
-    // Gender.
-    public final static int GENDER_UNKNOWN = 0;
-    public final static int GENDER_NEUTRAL = 1;
-    public final static int GENDER_MALE = 2;
-    public final static int GENDER_FEMALE = 3;
-
-    // Animacy.
-    public final static int ANIMACY_UNKNOWN = 0;
-    public final static int ANIMACY_ANIMATE = 1;
-    public final static int ANIMACY_INANIMATE = 2;
-
-    // Multiplicity.
-    public final static int MULTIPLICITY_UNKNOWN = 0;
-    public final static int MULTIPLICITY_SINGLE = 1;
-    public final static int MULTIPLICITY_DUAL = 2;
-    public final static int MULTIPLICITY_PLURAL = 3;
-
-    // Case.
-    public final static int CASE_UNKNOWN = 0;
-    public final static int CASE_NOMINATIVE = 1;
-    public final static int CASE_ACCUSATIVE = 2;
-    public final static int CASE_DATIVE = 3;
-    public final static int CASE_ABLATIVE = 4;
-    public final static int CASE_GENITIVE = 5;
-    public final static int CASE_VOCATIVE = 6;
-    public final static int CASE_LOCATIVE = 7;
-    public final static int CASE_INSTRUMENTAL = 8;
-
-    private List<AbstractTts<? extends AbstractTts<?>>> says =
-            new ArrayList<AbstractTts<? extends AbstractTts<?>>>();
-    Boolean mNoWarningOnFallback = null;
-
-    /**
-     * Objects deriving from this class can be appended to a Utterance. This class uses generics
-     * so method from this class can return instances of its child classes, resulting in a better
-     * API (CRTP pattern).
-     */
-    public static abstract class AbstractTts<C extends AbstractTts<C>> {
-
-        protected Markup mMarkup = new Markup();
-
-        /**
-         * Empty constructor.
-         */
-        protected AbstractTts() {
-        }
-
-        /**
-         * Construct with Markup.
-         * @param markup
-         */
-        protected AbstractTts(Markup markup) {
-            mMarkup = markup;
-        }
-
-        /**
-         * Returns the type of this class, e.g. "cardinal" or "measure".
-         * @return The type.
-         */
-        public String getType() {
-            return mMarkup.getType();
-        }
-
-        /**
-         * A fallback plain text can be provided, in case the engine does not support this class
-         * type, or even Markup altogether.
-         * @param plainText A string with the plain text.
-         * @return This instance.
-         */
-        @SuppressWarnings("unchecked")
-        public C setPlainText(String plainText) {
-            mMarkup.setPlainText(plainText);
-            return (C) this;
-        }
-
-        /**
-         * Returns the plain text (fallback) string.
-         * @return Plain text string or null if not set.
-         */
-        public String getPlainText() {
-            return mMarkup.getPlainText();
-        }
-
-        /**
-         * Populates the plainText if not set and builds a Markup instance.
-         * @return The Markup object describing this instance.
-         */
-        public Markup getMarkup() {
-            return new Markup(mMarkup);
-        }
-
-        @SuppressWarnings("unchecked")
-        protected C setParameter(String key, String value) {
-            mMarkup.setParameter(key, value);
-            return (C) this;
-        }
-
-        protected String getParameter(String key) {
-            return mMarkup.getParameter(key);
-        }
-
-        @SuppressWarnings("unchecked")
-        protected C removeParameter(String key) {
-            mMarkup.removeParameter(key);
-            return (C) this;
-        }
-
-        /**
-         * Returns a string representation of this instance, can be deserialized to an equal
-         * Utterance instance.
-         */
-        public String toString() {
-            return mMarkup.toString();
-        }
-
-        /**
-         * Returns a generated plain text alternative for this instance if this instance isn't
-         * better representated by the list of it's children.
-         * @return Best effort plain text representation of this instance, can be null.
-         */
-        public String generatePlainText() {
-            return null;
-        }
-    }
-
-    public static abstract class AbstractTtsSemioticClass<C extends AbstractTtsSemioticClass<C>>
-            extends AbstractTts<C> {
-        // Keys.
-        private static final String KEY_GENDER = "gender";
-        private static final String KEY_ANIMACY = "animacy";
-        private static final String KEY_MULTIPLICITY = "multiplicity";
-        private static final String KEY_CASE = "case";
-
-        protected AbstractTtsSemioticClass() {
-            super();
-        }
-
-        protected AbstractTtsSemioticClass(Markup markup) {
-            super(markup);
-        }
-
-        @SuppressWarnings("unchecked")
-        public C setGender(int gender) {
-            if (gender < 0 || gender > 3) {
-                throw new IllegalArgumentException("Only four types of gender can be set: " +
-                                                   "unknown, neutral, maculine and female.");
-            }
-            if (gender != GENDER_UNKNOWN) {
-                setParameter(KEY_GENDER, String.valueOf(gender));
-            } else {
-                setParameter(KEY_GENDER, null);
-            }
-            return (C) this;
-        }
-
-        public int getGender() {
-            String gender = mMarkup.getParameter(KEY_GENDER);
-            return gender != null ? Integer.valueOf(gender) : GENDER_UNKNOWN;
-        }
-
-        @SuppressWarnings("unchecked")
-        public C setAnimacy(int animacy) {
-            if (animacy < 0 || animacy > 2) {
-                throw new IllegalArgumentException(
-                        "Only two types of animacy can be set: unknown, animate and inanimate");
-            }
-            if (animacy != ANIMACY_UNKNOWN) {
-                setParameter(KEY_ANIMACY, String.valueOf(animacy));
-            } else {
-                setParameter(KEY_ANIMACY, null);
-            }
-            return (C) this;
-        }
-
-        public int getAnimacy() {
-            String animacy = getParameter(KEY_ANIMACY);
-            return animacy != null ? Integer.valueOf(animacy) : ANIMACY_UNKNOWN;
-        }
-
-        @SuppressWarnings("unchecked")
-        public C setMultiplicity(int multiplicity) {
-            if (multiplicity < 0 || multiplicity > 3) {
-                throw new IllegalArgumentException(
-                        "Only four types of multiplicity can be set: unknown, single, dual and " +
-                        "plural.");
-            }
-            if (multiplicity != MULTIPLICITY_UNKNOWN) {
-                setParameter(KEY_MULTIPLICITY, String.valueOf(multiplicity));
-            } else {
-                setParameter(KEY_MULTIPLICITY, null);
-            }
-            return (C) this;
-        }
-
-        public int getMultiplicity() {
-            String multiplicity = mMarkup.getParameter(KEY_MULTIPLICITY);
-            return multiplicity != null ? Integer.valueOf(multiplicity) : MULTIPLICITY_UNKNOWN;
-        }
-
-        @SuppressWarnings("unchecked")
-        public C setCase(int grammaticalCase) {
-            if (grammaticalCase < 0 || grammaticalCase > 8) {
-                throw new IllegalArgumentException(
-                        "Only nine types of grammatical case can be set.");
-            }
-            if (grammaticalCase != CASE_UNKNOWN) {
-                setParameter(KEY_CASE, String.valueOf(grammaticalCase));
-            } else {
-                setParameter(KEY_CASE, null);
-            }
-            return (C) this;
-        }
-
-        public int getCase() {
-            String grammaticalCase = mMarkup.getParameter(KEY_CASE);
-            return grammaticalCase != null ? Integer.valueOf(grammaticalCase) : CASE_UNKNOWN;
-        }
-    }
-
-    /**
-     * Class that contains regular text, synthesis engine pronounces it using its regular pipeline.
-     * Parameters:
-     * <ul>
-     *   <li>Text: the text to synthesize</li>
-     * </ul>
-     */
-    public static class TtsText extends AbstractTtsSemioticClass<TtsText> {
-
-        // The type of this node.
-        protected static final String TYPE_TEXT = "text";
-        // The text parameter stores the text to be synthesized.
-        private static final String KEY_TEXT = "text";
-
-        /**
-         * Default constructor.
-         */
-        public TtsText() {
-            mMarkup.setType(TYPE_TEXT);
-        }
-
-        /**
-         * Constructor that sets the text to be synthesized.
-         * @param text The text to be synthesized.
-         */
-        public TtsText(String text) {
-            this();
-            setText(text);
-        }
-
-        /**
-         * Constructs a TtsText with the values of the Markup, does not check if the given Markup is
-         * of the right type.
-         */
-        private TtsText(Markup markup) {
-            super(markup);
-        }
-
-        /**
-         * Sets the text to be synthesized.
-         * @return This instance.
-         */
-        public TtsText setText(String text) {
-            setParameter(KEY_TEXT, text);
-            return this;
-        }
-
-        /**
-         * Returns the text to be synthesized.
-         * @return This instance.
-         */
-        public String getText() {
-            return getParameter(KEY_TEXT);
-        }
-
-        /**
-         * Generates a best effort plain text, in this case simply the text.
-         */
-        @Override
-        public String generatePlainText() {
-            return getText();
-        }
-    }
-
-    /**
-     * Contains a cardinal.
-     * Parameters:
-     * <ul>
-     *   <li>integer: the integer to synthesize</li>
-     * </ul>
-     */
-    public static class TtsCardinal extends AbstractTtsSemioticClass<TtsCardinal> {
-
-        // The type of this node.
-        protected static final String TYPE_CARDINAL = "cardinal";
-        // The parameter integer stores the integer to synthesize.
-        private static final String KEY_INTEGER = "integer";
-
-        /**
-         * Default constructor.
-         */
-        public TtsCardinal() {
-            mMarkup.setType(TYPE_CARDINAL);
-        }
-
-        /**
-         * Constructor that sets the integer to be synthesized.
-         */
-        public TtsCardinal(int integer) {
-            this();
-            setInteger(integer);
-        }
-
-        /**
-         * Constructor that sets the integer to be synthesized.
-         */
-        public TtsCardinal(String integer) {
-            this();
-            setInteger(integer);
-        }
-
-        /**
-         * Constructs a TtsText with the values of the Markup.
-         * Does not check if the given Markup is of the right type.
-         */
-        private TtsCardinal(Markup markup) {
-            super(markup);
-        }
-
-        /**
-         * Sets the integer.
-         * @return This instance.
-         */
-        public TtsCardinal setInteger(int integer) {
-            return setInteger(String.valueOf(integer));
-        }
-
-        /**
-         * Sets the integer.
-         * @param integer A non-empty string of digits with an optional '-' in front.
-         * @return This instance.
-         */
-        public TtsCardinal setInteger(String integer) {
-            if (!integer.matches("-?\\d+")) {
-                throw new IllegalArgumentException("Expected a cardinal: \"" + integer + "\"");
-            }
-            setParameter(KEY_INTEGER, integer);
-            return this;
-        }
-
-        /**
-         * Returns the integer parameter.
-         */
-        public String getInteger() {
-            return getParameter(KEY_INTEGER);
-        }
-
-        /**
-         * Generates a best effort plain text, in this case simply the integer.
-         */
-        @Override
-        public String generatePlainText() {
-            return getInteger();
-        }
-    }
-
-    /**
-     * Default constructor.
-     */
-    public Utterance() {}
-
-    /**
-     * Returns the plain text of a given Markup if it was set; if it's not set, recursively call the
-     * this same method on its children.
-     */
-    private String constructPlainText(Markup m) {
-        StringBuilder plainText = new StringBuilder();
-        if (m.getPlainText() != null) {
-            plainText.append(m.getPlainText());
-        } else {
-            for (Markup nestedMarkup : m.getNestedMarkups()) {
-                String nestedPlainText = constructPlainText(nestedMarkup);
-                if (!nestedPlainText.isEmpty()) {
-                    if (plainText.length() != 0) {
-                        plainText.append(" ");
-                    }
-                    plainText.append(nestedPlainText);
-                }
-            }
-        }
-        return plainText.toString();
-    }
-
-    /**
-     * Creates a Markup instance with auto generated plain texts for the relevant nodes, in case the
-     * user has not provided one already.
-     * @return A Markup instance representing this utterance.
-     */
-    public Markup createMarkup() {
-        Markup markup = new Markup(TYPE_UTTERANCE);
-        StringBuilder plainText = new StringBuilder();
-        for (AbstractTts<? extends AbstractTts<?>> say : says) {
-            // Get a copy of this markup, and generate a plaintext for it if is not set.
-            Markup sayMarkup = say.getMarkup();
-            if (sayMarkup.getPlainText() == null) {
-                sayMarkup.setPlainText(say.generatePlainText());
-            }
-            if (plainText.length() != 0) {
-                plainText.append(" ");
-            }
-            plainText.append(constructPlainText(sayMarkup));
-            markup.addNestedMarkup(sayMarkup);
-        }
-        if (mNoWarningOnFallback != null) {
-            markup.setParameter(KEY_NO_WARNING_ON_FALLBACK,
-                                mNoWarningOnFallback ? "true" : "false");
-        }
-        markup.setPlainText(plainText.toString());
-        return markup;
-    }
-
-    /**
-     * Appends an element to this Utterance instance.
-     * @return this instance
-     */
-    public Utterance append(AbstractTts<? extends AbstractTts<?>> say) {
-        says.add(say);
-        return this;
-    }
-
-    private Utterance append(Markup markup) {
-        if (markup.getType().equals(TtsText.TYPE_TEXT)) {
-            append(new TtsText(markup));
-        } else if (markup.getType().equals(TtsCardinal.TYPE_CARDINAL)) {
-            append(new TtsCardinal(markup));
-        } else {
-            // Unknown node, a class we don't know about.
-            if (markup.getPlainText() != null) {
-                append(new TtsText(markup.getPlainText()));
-            } else {
-                // No plainText specified; add its children
-                // seperately. In case of a new prosody node,
-                // we would still verbalize it correctly.
-                for (Markup nested : markup.getNestedMarkups()) {
-                    append(nested);
-                }
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Returns a string representation of this Utterance instance. Can be deserialized back to an
-     * Utterance instance with utteranceFromString(). Can be used to store utterances to be used
-     * at a later time.
-     */
-    public String toString() {
-        String out = "type: \"" + TYPE_UTTERANCE + "\"";
-        if (mNoWarningOnFallback != null) {
-            out += " no_warning_on_fallback: \"" + (mNoWarningOnFallback ? "true" : "false") + "\"";
-        }
-        for (AbstractTts<? extends AbstractTts<?>> say : says) {
-            out += " markup { " + say.getMarkup().toString() + " }";
-        }
-        return out;
-    }
-
-    /**
-     * Returns an Utterance instance from the string representation generated by toString().
-     * @param string The string representation generated by toString().
-     * @return The new Utterance instance.
-     * @throws {@link IllegalArgumentException} if the input cannot be correctly parsed.
-     */
-    static public Utterance utteranceFromString(String string) throws IllegalArgumentException {
-        Utterance utterance = new Utterance();
-        Markup markup = Markup.markupFromString(string);
-        if (!markup.getType().equals(TYPE_UTTERANCE)) {
-            throw new IllegalArgumentException("Top level markup should be of type \"" +
-                                               TYPE_UTTERANCE + "\", but was of type \"" +
-                                               markup.getType() + "\".") ;
-        }
-        for (Markup nestedMarkup : markup.getNestedMarkups()) {
-            utterance.append(nestedMarkup);
-        }
-        return utterance;
-    }
-
-    /**
-     * Appends a new TtsText with the given text.
-     * @param text The text to synthesize.
-     * @return This instance.
-     */
-    public Utterance append(String text) {
-        return append(new TtsText(text));
-    }
-
-    /**
-     * Appends a TtsCardinal representing the given number.
-     * @param integer The integer to synthesize.
-     * @return this
-     */
-    public Utterance append(int integer) {
-        return append(new TtsCardinal(integer));
-    }
-
-    /**
-     * Returns the n'th element in this Utterance.
-     * @param i The index.
-     * @return The n'th element in this Utterance.
-     * @throws {@link IndexOutOfBoundsException} - if i < 0 || i >= size()
-     */
-    public AbstractTts<? extends AbstractTts<?>> get(int i) {
-        return says.get(i);
-    }
-
-    /**
-     * Returns the number of elements in this Utterance.
-     * @return The number of elements in this Utterance.
-     */
-    public int size() {
-        return says.size();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if ( this == o ) return true;
-        if ( !(o instanceof Utterance) ) return false;
-        Utterance utt = (Utterance) o;
-
-        if (says.size() != utt.says.size()) {
-            return false;
-        }
-
-        for (int i = 0; i < says.size(); i++) {
-            if (!says.get(i).getMarkup().equals(utt.says.get(i).getMarkup())) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Can be set to true or false, true indicating that the user provided only a string to the API,
-     * at which the system will not issue a warning if the synthesizer falls back onto the plain
-     * text when the synthesizer does not support Markup.
-     */
-    public Utterance setNoWarningOnFallback(boolean noWarning) {
-        mNoWarningOnFallback = noWarning;
-        return this;
-    }
-}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 44301c3..6d7c8034 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.SystemApi;
 import android.content.Context;
 
 /**
@@ -1500,6 +1501,7 @@
      * WebView.
      * @hide
      */
+    @SystemApi
     public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag);
 
     /**
@@ -1509,5 +1511,6 @@
      * @see #setVideoOverlayForEmbeddedEncryptedVideoEnabled
      * @hide
      */
+    @SystemApi
     public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index edbe9f4..01b7fde 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -51,6 +51,7 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
+import com.android.internal.widget.ResolverDrawerLayout;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -176,6 +177,16 @@
             mGridView.setVisibility(View.GONE);
         }
 
+        final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
+        if (rdl != null) {
+            rdl.setOnClickOutsideListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    finish();
+                }
+            });
+        }
+
         final TextView titleView = (TextView) findViewById(R.id.title);
         if (titleView != null) {
             titleView.setText(title);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
new file mode 100644
index 0000000..e53f9dd
--- /dev/null
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -0,0 +1,673 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
+import android.widget.AbsListView;
+import android.widget.OverScroller;
+import com.android.internal.R;
+
+public class ResolverDrawerLayout extends ViewGroup {
+    private static final String TAG = "ResolverDrawerLayout";
+
+    /**
+     * Max width of the whole drawer layout
+     */
+    private int mMaxWidth;
+
+    /**
+     * Max total visible height of views not marked always-show when in the closed/initial state
+     */
+    private int mMaxCollapsedHeight;
+
+    /**
+     * Max total visible height of views not marked always-show when in the closed/initial state
+     * when a default option is present
+     */
+    private int mMaxCollapsedHeightSmall;
+
+    private boolean mSmallCollapsed;
+
+    /**
+     * Move views down from the top by this much in px
+     */
+    private float mCollapseOffset;
+
+    private int mCollapsibleHeight;
+
+    private int mTopOffset;
+
+    private boolean mIsDragging;
+    private boolean mOpenOnClick;
+    private final int mTouchSlop;
+    private final float mMinFlingVelocity;
+    private final OverScroller mScroller;
+    private final VelocityTracker mVelocityTracker;
+
+    private OnClickListener mClickOutsideListener;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private float mLastTouchY;
+    private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+    private final Rect mTempRect = new Rect();
+
+    private final ViewTreeObserver.OnTouchModeChangeListener mTouchModeChangeListener =
+            new ViewTreeObserver.OnTouchModeChangeListener() {
+                @Override
+                public void onTouchModeChanged(boolean isInTouchMode) {
+                    if (!isInTouchMode && hasFocus() && isDescendantClipped(getFocusedChild())) {
+                        smoothScrollTo(0, 0);
+                    }
+                }
+            };
+
+    public ResolverDrawerLayout(Context context) {
+        this(context, null);
+    }
+
+    public ResolverDrawerLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ResolverDrawerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ResolverDrawerLayout,
+                defStyleAttr, 0);
+        mMaxWidth = a.getDimensionPixelSize(R.styleable.ResolverDrawerLayout_maxWidth, -1);
+        mMaxCollapsedHeight = a.getDimensionPixelSize(
+                R.styleable.ResolverDrawerLayout_maxCollapsedHeight, 0);
+        mMaxCollapsedHeightSmall = a.getDimensionPixelSize(
+                R.styleable.ResolverDrawerLayout_maxCollapsedHeightSmall,
+                mMaxCollapsedHeight);
+        a.recycle();
+
+        mScroller = new OverScroller(context, AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.decelerate_quint));
+        mVelocityTracker = VelocityTracker.obtain();
+
+        final ViewConfiguration vc = ViewConfiguration.get(context);
+        mTouchSlop = vc.getScaledTouchSlop();
+        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+    }
+
+    public void setSmallCollapsed(boolean smallCollapsed) {
+        mSmallCollapsed = smallCollapsed;
+        requestLayout();
+    }
+
+    public boolean isSmallCollapsed() {
+        return mSmallCollapsed;
+    }
+
+    public boolean isCollapsed() {
+        return mCollapseOffset > 0;
+    }
+
+    private boolean isMoving() {
+        return mIsDragging || !mScroller.isFinished();
+    }
+
+    private int getMaxCollapsedHeight() {
+        return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
+    }
+
+    public void setOnClickOutsideListener(OnClickListener listener) {
+        mClickOutsideListener = listener;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mVelocityTracker.clear();
+        }
+
+        mVelocityTracker.addMovement(ev);
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialTouchX = x;
+                mInitialTouchY = mLastTouchY = y;
+                mOpenOnClick = isListChildUnderClipped(x, y) && mCollapsibleHeight > 0;
+            }
+            break;
+
+            case MotionEvent.ACTION_MOVE: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                final float dy = y - mInitialTouchY;
+                if (Math.abs(dy) > mTouchSlop && findChildUnder(x, y) != null &&
+                        (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
+                    mActivePointerId = ev.getPointerId(0);
+                    mIsDragging = true;
+                    mLastTouchY = Math.max(mLastTouchY - mTouchSlop,
+                            Math.min(mLastTouchY + dy, mLastTouchY + mTouchSlop));
+                }
+            }
+            break;
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                onSecondaryPointerUp(ev);
+            }
+            break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP: {
+                resetTouch();
+            }
+            break;
+        }
+
+        if (mIsDragging) {
+            mScroller.abortAnimation();
+        }
+        return mIsDragging || mOpenOnClick;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+
+        boolean handled = false;
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialTouchX = x;
+                mInitialTouchY = mLastTouchY = y;
+                mActivePointerId = ev.getPointerId(0);
+                if (findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+                        mClickOutsideListener != null) {
+                    mIsDragging = handled = true;
+                }
+                handled |= mCollapsibleHeight > 0;
+                mScroller.abortAnimation();
+            }
+            break;
+
+            case MotionEvent.ACTION_MOVE: {
+                int index = ev.findPointerIndex(mActivePointerId);
+                if (index < 0) {
+                    Log.e(TAG, "Bad pointer id " + mActivePointerId + ", resetting");
+                    index = 0;
+                    mActivePointerId = ev.getPointerId(0);
+                    mInitialTouchX = ev.getX();
+                    mInitialTouchY = mLastTouchY = ev.getY();
+                }
+                final float x = ev.getX(index);
+                final float y = ev.getY(index);
+                if (!mIsDragging) {
+                    final float dy = y - mInitialTouchY;
+                    if (Math.abs(dy) > mTouchSlop && findChildUnder(x, y) != null) {
+                        handled = mIsDragging = true;
+                        mLastTouchY = Math.max(mLastTouchY - mTouchSlop,
+                                Math.min(mLastTouchY + dy, mLastTouchY + mTouchSlop));
+                    }
+                }
+                if (mIsDragging) {
+                    final float dy = y - mLastTouchY;
+                    performDrag(dy);
+                }
+                mLastTouchY = y;
+            }
+            break;
+
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int pointerIndex = ev.getActionIndex();
+                final int pointerId = ev.getPointerId(pointerIndex);
+                mActivePointerId = pointerId;
+                mInitialTouchX = ev.getX(pointerIndex);
+                mInitialTouchY = mLastTouchY = ev.getY(pointerIndex);
+            }
+            break;
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                onSecondaryPointerUp(ev);
+            }
+            break;
+
+            case MotionEvent.ACTION_UP: {
+                mIsDragging = false;
+                if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+                        findChildUnder(ev.getX(), ev.getY()) == null) {
+                    if (mClickOutsideListener != null) {
+                        mClickOutsideListener.onClick(this);
+                        resetTouch();
+                        return true;
+                    }
+                }
+                if (mOpenOnClick && Math.abs(ev.getX() - mInitialTouchX) < mTouchSlop &&
+                        Math.abs(ev.getY() - mInitialTouchY) < mTouchSlop) {
+                    smoothScrollTo(0, 0);
+                    return true;
+                }
+                mVelocityTracker.computeCurrentVelocity(1000);
+                final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
+                if (Math.abs(yvel) > mMinFlingVelocity) {
+                    smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+                } else {
+                    smoothScrollTo(
+                            mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
+                }
+                resetTouch();
+            }
+            break;
+
+            case MotionEvent.ACTION_CANCEL: {
+                resetTouch();
+                return true;
+            }
+        }
+
+        return handled;
+    }
+
+    private void onSecondaryPointerUp(MotionEvent ev) {
+        final int pointerIndex = ev.getActionIndex();
+        final int pointerId = ev.getPointerId(pointerIndex);
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mInitialTouchX = ev.getX(newPointerIndex);
+            mInitialTouchY = mLastTouchY = ev.getY(newPointerIndex);
+            mActivePointerId = ev.getPointerId(newPointerIndex);
+        }
+    }
+
+    private void resetTouch() {
+        mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+        mIsDragging = false;
+        mOpenOnClick = false;
+        mInitialTouchX = mInitialTouchY = mLastTouchY = 0;
+        mVelocityTracker.clear();
+    }
+
+    @Override
+    public void computeScroll() {
+        super.computeScroll();
+        if (!mScroller.isFinished()) {
+            final boolean keepGoing = mScroller.computeScrollOffset();
+            performDrag(mScroller.getCurrY() - mCollapseOffset);
+            if (keepGoing) {
+                postInvalidateOnAnimation();
+            }
+        }
+    }
+
+    private float performDrag(float dy) {
+        final float newPos = Math.max(0, Math.min(mCollapseOffset + dy, mCollapsibleHeight));
+        if (newPos != mCollapseOffset) {
+            dy = newPos - mCollapseOffset;
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.ignoreOffset) {
+                    child.offsetTopAndBottom((int) dy);
+                }
+            }
+            mCollapseOffset = newPos;
+            mTopOffset += dy;
+            postInvalidateOnAnimation();
+            return dy;
+        }
+        return 0;
+    }
+
+    private void smoothScrollTo(int yOffset, float velocity) {
+        if (getMaxCollapsedHeight() == 0) {
+            return;
+        }
+        mScroller.abortAnimation();
+        final int sy = (int) mCollapseOffset;
+        int dy = yOffset - sy;
+        if (dy == 0) {
+            return;
+        }
+
+        final int height = getHeight();
+        final int halfHeight = height / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / height);
+        final float distance = halfHeight + halfHeight *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration = 0;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float pageDelta = (float) Math.abs(dy) / height;
+            duration = (int) ((pageDelta + 1) * 100);
+        }
+        duration = Math.min(duration, 300);
+
+        mScroller.startScroll(0, sy, 0, dy, duration);
+        postInvalidateOnAnimation();
+    }
+
+    private float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    /**
+     * Note: this method doesn't take Z into account for overlapping views
+     * since it is only used in contexts where this doesn't affect the outcome.
+     */
+    private View findChildUnder(float x, float y) {
+        return findChildUnder(this, x, y);
+    }
+
+    private static View findChildUnder(ViewGroup parent, float x, float y) {
+        final int childCount = parent.getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            final View child = parent.getChildAt(i);
+            if (isChildUnder(child, x, y)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    private View findListChildUnder(float x, float y) {
+        View v = findChildUnder(x, y);
+        while (v != null) {
+            x -= v.getX();
+            y -= v.getY();
+            if (v instanceof AbsListView) {
+                // One more after this.
+                return findChildUnder((ViewGroup) v, x, y);
+            }
+            v = v instanceof ViewGroup ? findChildUnder((ViewGroup) v, x, y) : null;
+        }
+        return v;
+    }
+
+    /**
+     * This only checks clipping along the bottom edge.
+     */
+    private boolean isListChildUnderClipped(float x, float y) {
+        final View listChild = findListChildUnder(x, y);
+        return listChild != null && isDescendantClipped(listChild);
+    }
+
+    private boolean isDescendantClipped(View child) {
+        mTempRect.set(0, 0, child.getWidth(), child.getHeight());
+        offsetDescendantRectToMyCoords(child, mTempRect);
+        View directChild;
+        if (child.getParent() == this) {
+            directChild = child;
+        } else {
+            View v = child;
+            ViewParent p = child.getParent();
+            while (p != this) {
+                v = (View) p;
+                p = v.getParent();
+            }
+            directChild = v;
+        }
+
+        // ResolverDrawerLayout lays out vertically in child order;
+        // the next view and forward is what to check against.
+        int clipEdge = getHeight() - getPaddingBottom();
+        final int childCount = getChildCount();
+        for (int i = indexOfChild(directChild) + 1; i < childCount; i++) {
+            final View nextChild = getChildAt(i);
+            if (nextChild.getVisibility() == GONE) {
+                continue;
+            }
+            clipEdge = Math.min(clipEdge, nextChild.getTop());
+        }
+        return mTempRect.bottom > clipEdge;
+    }
+
+    private static boolean isChildUnder(View child, float x, float y) {
+        final float left = child.getX();
+        final float top = child.getY();
+        final float right = left + child.getWidth();
+        final float bottom = top + child.getHeight();
+        return x >= left && y >= top && x < right && y < bottom;
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        super.requestChildFocus(child, focused);
+        if (!isInTouchMode() && isDescendantClipped(focused)) {
+            smoothScrollTo(0, 0);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnTouchModeChangeListener(mTouchModeChangeListener);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getViewTreeObserver().removeOnTouchModeChangeListener(mTouchModeChangeListener);
+    }
+
+    @Override
+    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+        return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0;
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int axes) {
+        super.onNestedScrollAccepted(child, target, axes);
+    }
+
+    @Override
+    public void onStopNestedScroll(View child) {
+        super.onStopNestedScroll(child);
+        smoothScrollTo(mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed) {
+        if (dyUnconsumed > 0) {
+            performDrag(-dyUnconsumed);
+        }
+    }
+
+    @Override
+    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+        if (dy < 0) {
+            consumed[1] = (int) performDrag(-dy);
+        }
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
+            smoothScrollTo(velocityY < 0 ? 0 : mCollapsibleHeight, velocityY);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int widthSize = sourceWidth;
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        // Single-use layout; just ignore the mode and use available space.
+        // Clamp to maxWidth.
+        if (mMaxWidth >= 0) {
+            widthSize = Math.min(widthSize, mMaxWidth);
+        }
+
+        final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
+        final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
+        final int widthPadding = getPaddingLeft() + getPaddingRight();
+        int heightUsed = getPaddingTop() + getPaddingBottom();
+
+        // Measure always-show children first.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.alwaysShow && child.getVisibility() != GONE) {
+                measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+            }
+        }
+
+        final int alwaysShowHeight = heightUsed;
+
+        // And now the rest.
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (!lp.alwaysShow && child.getVisibility() != GONE) {
+                measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+            }
+        }
+
+        mCollapsibleHeight = Math.max(0,
+                heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
+
+        if (isLaidOut()) {
+            mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+        } else {
+            // Start out collapsed at first
+            mCollapseOffset = mCollapsibleHeight;
+        }
+
+        mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
+
+        setMeasuredDimension(sourceWidth, heightSize);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int width = getWidth();
+
+        int ypos = mTopOffset;
+        int leftEdge = getPaddingLeft();
+        int rightEdge = width - getPaddingRight();
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            int top = ypos + lp.topMargin;
+            if (lp.ignoreOffset) {
+                top -= mCollapseOffset;
+            }
+            final int bottom = top + child.getMeasuredHeight();
+
+            final int childWidth = child.getMeasuredWidth();
+            final int widthAvailable = rightEdge - leftEdge;
+            final int left = leftEdge + (widthAvailable - childWidth) / 2;
+            final int right = left + childWidth;
+
+            child.layout(left, top, right, bottom);
+
+            ypos = bottom + lp.bottomMargin;
+        }
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) p);
+        } else if (p instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) p);
+        }
+        return new LayoutParams(p);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    public static class LayoutParams extends MarginLayoutParams {
+        public boolean alwaysShow;
+        public boolean ignoreOffset;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs,
+                    R.styleable.ResolverDrawerLayout_LayoutParams);
+            alwaysShow = a.getBoolean(
+                    R.styleable.ResolverDrawerLayout_LayoutParams_layout_alwaysShow,
+                    false);
+            ignoreOffset = a.getBoolean(
+                    R.styleable.ResolverDrawerLayout_LayoutParams_layout_ignoreOffset,
+                    false);
+            a.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+            this.alwaysShow = source.alwaysShow;
+            this.ignoreOffset = source.ignoreOffset;
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+    }
+}
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 40bae71..773b386 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -16,47 +16,53 @@
 * limitations under the License.
 */
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.ResolverDrawerLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:maxWidth="400dp"
+    android:maxCollapsedHeight="260dp"
+    android:maxCollapsedHeightSmall="56dp"
+    android:id="@id/contentPanel"
+    >
+
+    <TextView android:id="@+id/title"
+              android:layout_width="match_parent"
+              android:layout_height="?android:attr/listPreferredItemHeight"
+              android:layout_alwaysShow="true"
+              android:textAppearance="?android:attr/textAppearanceLarge"
+              android:gravity="start|center_vertical"
+              android:paddingLeft="32dp"
+              android:paddingRight="32dp"
+              android:background="@color/white"
+              android:elevation="8dp"
+              />
+
+    <GridView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/resolver_list"
+        android:numColumns="4"
+        android:columnWidth="128dp"
+        android:clipToPadding="false"
+        android:scrollbarStyle="outsideOverlay"
+        android:paddingLeft="32dp"
+        android:paddingRight="32dp"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        android:background="@color/white"
+        android:elevation="8dp"
+        android:nestedScrollingEnabled="true"
+        />
+
+    <TextView android:id="@+id/empty"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
-              android:orientation="vertical"
-              >
-    <Space android:layout_width="0dp"
-           android:layout_height="0dp"
-           android:layout_weight="1" />
-
-    <!-- TODO Drawer-thing -->
-    <LinearLayout android:layout_width="match_parent"
-                 android:layout_height="wrap_content"
-                 android:layout_weight="1"
-                 android:orientation="vertical"
-                 android:paddingLeft="32dp"
-                 android:paddingRight="32dp"
-                 android:background="@color/white"
-                 android:elevation="8dp">
-
-        <TextView android:id="@+id/title"
-                  android:layout_width="match_parent"
-                  android:layout_height="?android:attr/listPreferredItemHeight"
-                  android:textAppearance="?android:attr/textAppearanceLarge"
-                  android:gravity="start|center_vertical" />
-
-        <GridView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:id="@+id/resolver_list"
-            android:numColumns="4"
-            android:columnWidth="128dp"
-            android:clipToPadding="false"
-            android:scrollbarStyle="outsideOverlay" />
-
-        <TextView android:id="@+id/empty"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:text="@string/noApplications"
-                  android:visibility="gone" />
-
-    </LinearLayout>
+              android:layout_alwaysShow="true"
+              android:text="@string/noApplications"
+              android:padding="32dp"
+              android:gravity="center"
+              android:visibility="gone" />
 
     <LinearLayout
         android:id="@+id/button_bar"
@@ -64,22 +70,24 @@
         style="?android:attr/buttonBarStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_ignoreOffset="true"
+        android:layout_alwaysShow="true"
         android:gravity="end"
         android:orientation="horizontal"
         android:layoutDirection="locale"
         android:measureWithLargestChild="true"
         android:background="@color/white"
+        android:paddingBottom="16dp"
+        android:paddingStart="32dp"
+        android:paddingEnd="32dp"
         android:elevation="8dp">
         <Button android:id="@+id/button_once"
                 android:layout_width="wrap_content"
                 android:layout_gravity="start"
                 android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
+                style="?android:attr/buttonBarNegativeButtonStyle"
                 android:minHeight="@dimen/alert_dialog_button_bar_height"
                 android:layout_height="wrap_content"
-                android:paddingStart="8dp"
-                android:paddingEnd="8dp"
                 android:enabled="false"
                 android:text="@string/activity_resolver_use_once"
                 android:onClick="onButtonClick" />
@@ -88,15 +96,11 @@
                 android:layout_gravity="end"
                 android:maxLines="2"
                 android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:paddingStart="8dp"
-                android:paddingEnd="8dp"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textColor="@color/material_blue_500"
-                android:textSize="14sp"
+                style="?android:attr/buttonBarPositiveButtonStyle"
                 android:layout_height="wrap_content"
                 android:enabled="false"
                 android:text="@string/activity_resolver_use_always"
                 android:onClick="onButtonClick" />
     </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4b708a7..ea9e189 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7111,4 +7111,16 @@
             <enum name="passthrough" value="3" />
         </attr>
     </declare-styleable>
+
+    <declare-styleable name="ResolverDrawerLayout">
+        <attr name="maxWidth" />
+        <attr name="maxCollapsedHeight" format="dimension" />
+        <attr name="maxCollapsedHeightSmall" format="dimension" />
+    </declare-styleable>
+
+    <declare-styleable name="ResolverDrawerLayout_LayoutParams">
+        <attr name="layout_alwaysShow" format="boolean" />
+        <attr name="layout_ignoreOffset" format="boolean" />
+        <attr name="layout_gravity" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 1a99f8c..ee2c7df 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -565,8 +565,10 @@
         <item name="windowIsTranslucent">true</item>
         <item name="windowNoTitle">true</item>
         <item name="windowBackground">@color/transparent</item>
-        <item name="statusBarColor">@color/black</item>
-        <item name="navigationBarColor">@color/black</item>
+        <item name="backgroundDimEnabled">true</item>
+        <item name="windowTranslucentStatus">false</item>
+        <item name="windowTranslucentNavigation">false</item>
+        <item name="windowDrawsSystemBarBackgrounds">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
     </style>
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index c96d0c8d..c9330c5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -32,62 +32,93 @@
         boolean isValid(byte[] params);
     }
 
-    final SparseArray<ParameterValidator> mValidators = new SparseArray<>();
+    // Only the direct addressing is allowed.
+    private static final int DEST_DIRECT = 1 << 0;
+    // Only the broadcast addressing is allowed.
+    private static final int DEST_BROADCAST = 1 << 1;
+    // Both the direct and the broadcast addressing are allowed.
+    private static final int DEST_ALL = DEST_DIRECT | DEST_BROADCAST;
+    // True if the messages from address 15 (unregistered) are allowed.
+    private static final int SRC_UNREGISTERED = 1 << 2;
+
+    private static class ValidationInfo {
+        public final ParameterValidator parameterValidator;
+        public final int addressType;
+
+        public ValidationInfo(ParameterValidator validator, int type) {
+            parameterValidator = validator;
+            addressType = type;
+        }
+    }
+
+    final SparseArray<ValidationInfo> mValidationInfo = new SparseArray<>();
 
     public HdmiCecMessageValidator(HdmiControlService service) {
         mService = service;
 
         // Messages related to the physical address.
         PhysicalAddressValidator physicalAddressValidator = new PhysicalAddressValidator();
-        mValidators.append(Constants.MESSAGE_ACTIVE_SOURCE, physicalAddressValidator);
-        mValidators.append(Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressValidator);
-        mValidators.append(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
-                new ReportPhysicalAddressValidator());
-        mValidators.append(Constants.MESSAGE_ROUTING_CHANGE, new RoutingChangeValidator());
-        mValidators.append(Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressValidator);
-        mValidators.append(Constants.MESSAGE_SET_STREAM_PATH, physicalAddressValidator);
-        mValidators.append(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, physicalAddressValidator);
+        addValidationInfo(Constants.MESSAGE_ACTIVE_SOURCE,
+                physicalAddressValidator, DEST_BROADCAST | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+                new ReportPhysicalAddressValidator(), DEST_BROADCAST | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_ROUTING_CHANGE,
+                new RoutingChangeValidator(), DEST_BROADCAST | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_ROUTING_INFORMATION,
+                physicalAddressValidator, DEST_BROADCAST | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_SET_STREAM_PATH,
+                physicalAddressValidator, DEST_BROADCAST);
+        addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+                physicalAddressValidator, DEST_DIRECT);
 
         // Messages have no parameter.
         FixedLengthValidator noneValidator = new FixedLengthValidator(0);
-        mValidators.append(Constants.MESSAGE_ABORT, noneValidator);
-        mValidators.append(Constants.MESSAGE_GET_CEC_VERSION, noneValidator);
-        mValidators.append(Constants.MESSAGE_GET_MENU_LANGUAGE, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_AUDIO_STATUS, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_OSD_NAME, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, noneValidator);
-        mValidators.append(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, noneValidator);
-        mValidators.append(Constants.MESSAGE_IMAGE_VIEW_ON, noneValidator);
-        mValidators.append(Constants.MESSAGE_INITIATE_ARC, noneValidator);
-        mValidators.append(Constants.MESSAGE_RECORD_OFF, noneValidator);
-        mValidators.append(Constants.MESSAGE_RECORD_TV_SCREEN, noneValidator);
-        mValidators.append(Constants.MESSAGE_REPORT_ARC_INITIATED, noneValidator);
-        mValidators.append(Constants.MESSAGE_REPORT_ARC_TERMINATED, noneValidator);
-        mValidators.append(Constants.MESSAGE_REQUEST_ARC_INITIATION, noneValidator);
-        mValidators.append(Constants.MESSAGE_REQUEST_ARC_TERMINATION, noneValidator);
-        mValidators.append(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, noneValidator);
-        mValidators.append(Constants.MESSAGE_STANDBY, noneValidator);
-        mValidators.append(Constants.MESSAGE_TERMINATE_ARC, noneValidator);
-        mValidators.append(Constants.MESSAGE_TEXT_VIEW_ON, noneValidator);
-        mValidators.append(Constants.MESSAGE_TUNER_STEP_DECREMENT, noneValidator);
-        mValidators.append(Constants.MESSAGE_TUNER_STEP_INCREMENT, noneValidator);
-        mValidators.append(Constants.MESSAGE_USER_CONTROL_RELEASED, noneValidator);
-        mValidators.append(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP, noneValidator);
+        addValidationInfo(Constants.MESSAGE_ABORT, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_GET_CEC_VERSION, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_GET_MENU_LANGUAGE,
+                noneValidator, DEST_DIRECT | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_GIVE_AUDIO_STATUS, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID,
+                noneValidator, DEST_DIRECT | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_GIVE_OSD_NAME, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS,
+                noneValidator, DEST_DIRECT | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
+                noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_IMAGE_VIEW_ON, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_INITIATE_ARC, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_RECORD_OFF, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_RECORD_TV_SCREEN, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REPORT_ARC_INITIATED, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REPORT_ARC_TERMINATED, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REQUEST_ARC_INITIATION, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REQUEST_ARC_TERMINATION, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE,
+                noneValidator, DEST_BROADCAST | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_STANDBY, noneValidator, DEST_ALL | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_TERMINATE_ARC, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_TEXT_VIEW_ON, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_TUNER_STEP_DECREMENT, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_TUNER_STEP_INCREMENT, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_USER_CONTROL_RELEASED, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP, noneValidator, DEST_ALL);
 
         // TODO: Validate more than length for the following messages.
 
         // Messages for the One Touch Record.
         FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
-        mValidators.append(Constants.MESSAGE_RECORD_ON, new VariableLengthValidator(1, 8));
-        mValidators.append(Constants.MESSAGE_RECORD_STATUS, oneByteValidator);
+        addValidationInfo(Constants.MESSAGE_RECORD_ON,
+                new VariableLengthValidator(1, 8), DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_RECORD_STATUS, oneByteValidator, DEST_DIRECT);
 
         // TODO: Handle messages for the Timer Programming.
 
         // Messages for the System Information.
-        mValidators.append(Constants.MESSAGE_CEC_VERSION, oneByteValidator);
-        mValidators.append(Constants.MESSAGE_SET_MENU_LANGUAGE, new FixedLengthValidator(3));
+        addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
+                new FixedLengthValidator(3), DEST_BROADCAST);
 
         // TODO: Handle messages for the Deck Control.
 
@@ -95,53 +126,92 @@
 
         // Messages for the Vendor Specific Commands.
         VariableLengthValidator maxLengthValidator = new VariableLengthValidator(0, 14);
-        mValidators.append(Constants.MESSAGE_DEVICE_VENDOR_ID, new FixedLengthValidator(3));
-        mValidators.append(Constants.MESSAGE_VENDOR_COMMAND, maxLengthValidator);
-        mValidators.append(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, maxLengthValidator);
-        mValidators.append(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, maxLengthValidator);
+        addValidationInfo(Constants.MESSAGE_DEVICE_VENDOR_ID,
+                new FixedLengthValidator(3), DEST_BROADCAST);
+        // Allow unregistered source for all vendor specific commands, because we don't know
+        // how to use the commands at this moment.
+        addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND,
+                maxLengthValidator, DEST_DIRECT | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
+                maxLengthValidator, DEST_ALL | SRC_UNREGISTERED);
+        addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
+                maxLengthValidator, DEST_ALL | SRC_UNREGISTERED);
 
         // Messages for the OSD.
-        mValidators.append(Constants.MESSAGE_SET_OSD_STRING, maxLengthValidator);
-        mValidators.append(Constants.MESSAGE_SET_OSD_NAME, maxLengthValidator);
+        addValidationInfo(Constants.MESSAGE_SET_OSD_STRING, maxLengthValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_SET_OSD_NAME, maxLengthValidator, DEST_DIRECT);
 
         // TODO: Handle messages for the Device Menu Control.
 
         // Messages for the Remote Control Passthrough.
         // TODO: Parse the first parameter and determine if it can have the next parameter.
-        mValidators.append(Constants.MESSAGE_USER_CONTROL_PRESSED,
-                new VariableLengthValidator(1, 2));
+        addValidationInfo(Constants.MESSAGE_USER_CONTROL_PRESSED,
+                new VariableLengthValidator(1, 2), DEST_DIRECT);
 
         // Messages for the Power Status.
-        mValidators.append(Constants.MESSAGE_REPORT_POWER_STATUS, oneByteValidator);
+        addValidationInfo(Constants.MESSAGE_REPORT_POWER_STATUS, oneByteValidator, DEST_DIRECT);
 
         // Messages for the General Protocol.
-        mValidators.append(Constants.MESSAGE_FEATURE_ABORT, new FixedLengthValidator(2));
+        addValidationInfo(Constants.MESSAGE_FEATURE_ABORT,
+                new FixedLengthValidator(2), DEST_DIRECT);
 
         // Messages for the System Audio Control.
-        mValidators.append(Constants.MESSAGE_REPORT_AUDIO_STATUS, oneByteValidator);
-        mValidators.append(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
-                new FixedLengthValidator(3));
-        mValidators.append(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, oneByteValidator);
-        mValidators.append(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, oneByteValidator);
-        mValidators.append(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, oneByteValidator);
+        addValidationInfo(Constants.MESSAGE_REPORT_AUDIO_STATUS, oneByteValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
+                new FixedLengthValidator(3), DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
+                oneByteValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, oneByteValidator, DEST_ALL);
+        addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
+                oneByteValidator, DEST_DIRECT);
 
         // Messages for the Audio Rate Control.
-        mValidators.append(Constants.MESSAGE_SET_AUDIO_RATE, oneByteValidator);
+        addValidationInfo(Constants.MESSAGE_SET_AUDIO_RATE, oneByteValidator, DEST_DIRECT);
 
         // All Messages for the ARC have no parameters.
 
         // Messages for the Capability Discovery and Control.
-        mValidators.append(Constants.MESSAGE_CDC_MESSAGE, maxLengthValidator);
+        addValidationInfo(Constants.MESSAGE_CDC_MESSAGE, maxLengthValidator,
+                DEST_BROADCAST | SRC_UNREGISTERED);
+    }
+
+    private void addValidationInfo(int opcode, ParameterValidator validator, int addrType) {
+        mValidationInfo.append(opcode, new ValidationInfo(validator, addrType));
     }
 
     boolean isValid(HdmiCecMessage message) {
         int opcode = message.getOpcode();
-        ParameterValidator validator = mValidators.get(opcode);
-        if (validator == null) {
-            Slog.i(TAG, "No validator for the message: " + message);
+        ValidationInfo info = mValidationInfo.get(opcode);
+        if (info == null) {
+            Slog.w(TAG, "No validation information for the message: " + message);
             return true;
         }
-        return validator.isValid(message.getParams());
+
+        // Check the source field.
+        if (message.getSource() == Constants.ADDR_UNREGISTERED &&
+                (info.addressType & SRC_UNREGISTERED) == 0) {
+            Slog.w(TAG, "Unexpected source: " + message);
+            return false;
+        }
+        // Check the destination field.
+        if (message.getDestination() == Constants.ADDR_BROADCAST) {
+            if ((info.addressType & DEST_BROADCAST) == 0) {
+                Slog.w(TAG, "Unexpected broadcast message: " + message);
+                return false;
+            }
+        } else {  // Direct addressing.
+            if ((info.addressType & DEST_DIRECT) == 0) {
+                Slog.w(TAG, "Unexpected direct message: " + message);
+                return false;
+            }
+        }
+
+        // Check the parameter type.
+        if (!info.parameterValidator.isValid(message.getParams())) {
+            Slog.w(TAG, "Unexpected parameters: " + message);
+            return false;
+        }
+        return true;
     }
 
     private static class FixedLengthValidator implements ParameterValidator {
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 770e385..2fd001a 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -41,7 +41,7 @@
         void onPostDialWait(Connection c, String remaining);
         void onRequestingRingback(Connection c, boolean ringback);
         void onDestroyed(Connection c);
-        void onConferenceCapableChanged(Connection c, boolean isConferenceCapable);
+        void onCallCapabilitiesChanged(Connection c, int callCapabilities);
         void onParentConnectionChanged(Connection c, Connection parent);
         void onSetCallVideoProvider(Connection c, CallVideoProvider callVideoProvider);
         void onSetAudioModeIsVoip(Connection c, boolean isVoip);
@@ -76,7 +76,7 @@
         public void onRequestingRingback(Connection c, boolean ringback) {}
 
         @Override
-        public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {}
+        public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {}
 
         @Override
         public void onParentConnectionChanged(Connection c, Connection parent) {}
@@ -110,7 +110,7 @@
     private CallAudioState mCallAudioState;
     private Uri mHandle;
     private boolean mRequestingRingback = false;
-    private boolean mIsConferenceCapable = false;
+    private int mCallCapabilities;
     private Connection mParentConnection;
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
@@ -279,10 +279,10 @@
     }
 
     /**
-     * Returns whether this connection is capable of being conferenced.
+     * Returns the connection's {@link CallCapabilities}
      */
-    public final boolean isConferenceCapable() {
-        return mIsConferenceCapable;
+    public final int getCallCapabilities() {
+        return mCallCapabilities;
     }
 
     /**
@@ -394,13 +394,15 @@
     }
 
     /**
-     * TODO(santoscordon): Needs documentation.
+     * Sets the connection's {@link CallCapabilities}.
+     *
+     * @param callCapabilities The new call capabilities.
      */
-    public final void setIsConferenceCapable(boolean isConferenceCapable) {
-        if (mIsConferenceCapable != isConferenceCapable) {
-            mIsConferenceCapable = isConferenceCapable;
+    public final void setCallCapabilities(int callCapabilities) {
+        if (mCallCapabilities != callCapabilities) {
+            mCallCapabilities = callCapabilities;
             for (Listener l : mListeners) {
-                l.onConferenceCapableChanged(this, mIsConferenceCapable);
+                l.onCallCapabilitiesChanged(this, mCallCapabilities);
             }
         }
     }
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 905304e..1bc184b 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -346,9 +346,9 @@
         }
 
         @Override
-        public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {
+        public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {
             String id = mIdByConnection.get(c);
-            mAdapter.setCanConference(id, isConferenceCapable);
+            mAdapter.setCallCapabilities(id, callCapabilities);
         }
 
         /** ${inheritDoc} */
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 890513f..b60e7c6 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -221,16 +221,10 @@
         }
     }
 
-    /**
-     * Indicates that the specified call can conference with any of the specified list of calls.
-     *
-     * @param callId The unique ID of the call.
-     * @param canConference Specified whether or not the call can be conferenced.
-     */
-    void setCanConference(String callId, boolean canConference) {
+    void setCallCapabilities(String callId, int capabilities) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.setCanConference(callId, canConference);
+                adapter.setCallCapabilities(callId, capabilities);
             } catch (RemoteException ignored) {
             }
         }
diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java
index 665a864..8ef283a 100644
--- a/telecomm/java/android/telecomm/RemoteConnection.java
+++ b/telecomm/java/android/telecomm/RemoteConnection.java
@@ -35,6 +35,7 @@
         void onStateChanged(RemoteConnection connection, int state);
         void onDisconnected(RemoteConnection connection, int cause, String message);
         void onRequestingRingback(RemoteConnection connection, boolean ringback);
+        void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities);
         void onPostDialWait(RemoteConnection connection, String remainingDigits);
         void onFeaturesChanged(RemoteConnection connection, int features);
         void onSetAudioModeIsVoip(RemoteConnection connection, boolean isVoip);
@@ -51,6 +52,7 @@
     private String mDisconnectMessage;
     private boolean mRequestingRingback;
     private boolean mConnected;
+    private int mCallCapabilities;
     private int mFeatures;
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
@@ -85,6 +87,10 @@
         return mDisconnectMessage;
     }
 
+    public int getCallCapabilities() {
+        return mCallCapabilities;
+    }
+
     public int getFeatures() {
         return mFeatures;
     }
@@ -229,6 +235,16 @@
     /**
      * @hide
      */
+    void setCallCapabilities(int callCapabilities) {
+        mCallCapabilities = callCapabilities;
+        for (Listener l : mListeners) {
+            l.onCallCapabilitiesChanged(this, callCapabilities);
+        }
+    }
+
+    /**
+     * @hide
+     */
     void setDestroyed() {
         if (!mListeners.isEmpty()) {
             // Make sure that the listeners are notified that the call is destroyed first.
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 42a9f5f..c22005b 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -144,8 +144,10 @@
 
         /** ${inheritDoc} */
         @Override
-        public void setCanConference(String connectionId, boolean canConference) {
-            // not supported for remote connections.
+        public void setCallCapabilities(String connectionId, int callCapabilities) {
+            if (isCurrentConnection(connectionId)) {
+                mConnection.setCallCapabilities(callCapabilities);
+            }
         }
 
         /** ${inheritDoc} */
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
index 47cc78e..e724bfb 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
@@ -50,7 +50,7 @@
 
     void setRequestingRingback(String callId, boolean ringing);
 
-    void setCanConference(String callId, boolean canConference);
+    void setCallCapabilities(String callId, int callCapabilities);
 
     void setIsConferenced(String callId, String conferenceCallId);
 
diff --git a/tests/TtsTests/src/com/android/speech/tts/AbstractTtsSemioticClassTest.java b/tests/TtsTests/src/com/android/speech/tts/AbstractTtsSemioticClassTest.java
deleted file mode 100644
index 31484f4..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/AbstractTtsSemioticClassTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import android.test.InstrumentationTestCase;
-
-import android.speech.tts.Markup;
-import android.speech.tts.Utterance;
-import android.speech.tts.Utterance.AbstractTtsSemioticClass;
-
-public class AbstractTtsSemioticClassTest extends InstrumentationTestCase {
-
-    public static class TtsMock extends AbstractTtsSemioticClass<TtsMock> {
-        public TtsMock() {
-            super();
-        }
-
-        public TtsMock(Markup markup) {
-            super();
-        }
-
-        public void setType(String type) {
-            mMarkup.setType(type);
-        }
-    }
-
-    public void testFluentAPI() {
-        new TtsMock()
-            .setPlainText("a plaintext") // from AbstractTts
-            .setGender(Utterance.GENDER_MALE) // from AbstractTtsSemioticClass
-            .setType("test"); // from TtsMock
-    }
-
-    public void testDefaultConstructor() {
-        new TtsMock();
-    }
-
-    public void testMarkupConstructor() {
-        Markup markup = new Markup();
-        new TtsMock(markup);
-    }
-
-    public void testGetType() {
-        TtsMock t = new TtsMock();
-        t.setType("type1");
-        assertEquals("type1", t.getType());
-        t.setType(null);
-        assertEquals(null, t.getType());
-        t.setType("type2");
-        assertEquals("type2", t.getType());
-    }
-
-
-    public void testDefaultGender() {
-        assertEquals(Utterance.GENDER_UNKNOWN, new TtsMock().getGender());
-    }
-
-    public void testSetGender() {
-        assertEquals(Utterance.GENDER_MALE,
-                     new TtsMock().setGender(Utterance.GENDER_MALE).getGender());
-    }
-
-    public void testSetGenderNegative() {
-        try {
-            new TtsMock().setGender(-1);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testSetGenderOutOfBounds() {
-        try {
-            new TtsMock().setGender(4);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testDefaultAnimacy() {
-        assertEquals(Utterance.ANIMACY_UNKNOWN, new TtsMock().getAnimacy());
-    }
-
-    public void testSetAnimacy() {
-        assertEquals(Utterance.ANIMACY_ANIMATE,
-                     new TtsMock().setAnimacy(Utterance.ANIMACY_ANIMATE).getAnimacy());
-    }
-
-    public void testSetAnimacyNegative() {
-        try {
-            new TtsMock().setAnimacy(-1);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testSetAnimacyOutOfBounds() {
-        try {
-            new TtsMock().setAnimacy(4);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testDefaultMultiplicity() {
-        assertEquals(Utterance.MULTIPLICITY_UNKNOWN, new TtsMock().getMultiplicity());
-    }
-
-    public void testSetMultiplicity() {
-        assertEquals(Utterance.MULTIPLICITY_DUAL,
-                     new TtsMock().setMultiplicity(Utterance.MULTIPLICITY_DUAL).getMultiplicity());
-    }
-
-    public void testSetMultiplicityNegative() {
-        try {
-            new TtsMock().setMultiplicity(-1);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testSetMultiplicityOutOfBounds() {
-        try {
-            new TtsMock().setMultiplicity(4);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testDefaultCase() {
-        assertEquals(Utterance.CASE_UNKNOWN, new TtsMock().getCase());
-    }
-
-    public void testSetCase() {
-        assertEquals(Utterance.CASE_VOCATIVE,
-                     new TtsMock().setCase(Utterance.CASE_VOCATIVE).getCase());
-    }
-
-    public void testSetCaseNegative() {
-        try {
-            new TtsMock().setCase(-1);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testSetCaseOutOfBounds() {
-        try {
-            new TtsMock().setCase(9);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testToString() {
-        TtsMock t = new TtsMock()
-            .setAnimacy(Utterance.ANIMACY_INANIMATE)
-            .setCase(Utterance.CASE_INSTRUMENTAL)
-            .setGender(Utterance.GENDER_FEMALE)
-            .setMultiplicity(Utterance.MULTIPLICITY_PLURAL);
-        String str =
-            "animacy: \"2\" " +
-            "case: \"8\" " +
-            "gender: \"3\" " +
-            "multiplicity: \"3\"";
-        assertEquals(str, t.toString());
-    }
-
-    public void testToStringSetToUnkown() {
-        TtsMock t = new TtsMock()
-            .setAnimacy(Utterance.ANIMACY_INANIMATE)
-            .setCase(Utterance.CASE_INSTRUMENTAL)
-            .setGender(Utterance.GENDER_FEMALE)
-            .setMultiplicity(Utterance.MULTIPLICITY_PLURAL)
-        // set back to unknown
-            .setAnimacy(Utterance.ANIMACY_UNKNOWN)
-            .setCase(Utterance.CASE_UNKNOWN)
-            .setGender(Utterance.GENDER_UNKNOWN)
-            .setMultiplicity(Utterance.MULTIPLICITY_UNKNOWN);
-        String str = "";
-        assertEquals(str, t.toString());
-    }
-
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/AbstractTtsTest.java b/tests/TtsTests/src/com/android/speech/tts/AbstractTtsTest.java
deleted file mode 100644
index 281c97f..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/AbstractTtsTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import android.test.InstrumentationTestCase;
-
-import android.speech.tts.Markup;
-import android.speech.tts.Utterance.AbstractTts;
-
-public class AbstractTtsTest extends InstrumentationTestCase {
-
-    public static class TtsMock extends AbstractTts<TtsMock> {
-        public TtsMock() {
-            super();
-        }
-
-        public TtsMock(Markup markup) {
-            super();
-        }
-
-        public void setType(String type) {
-            mMarkup.setType(type);
-        }
-
-        @Override
-        public TtsMock setParameter(String key, String value) {
-           return super.setParameter(key, value);
-        }
-
-        @Override
-        public TtsMock removeParameter(String key) {
-           return super.removeParameter(key);
-        }
-    }
-
-    public void testDefaultConstructor() {
-        new TtsMock();
-    }
-
-    public void testMarkupConstructor() {
-        Markup markup = new Markup();
-        new TtsMock(markup);
-    }
-
-    public void testGetType() {
-        TtsMock t = new TtsMock();
-        t.setType("type1");
-        assertEquals("type1", t.getType());
-        t.setType(null);
-        assertEquals(null, t.getType());
-        t.setType("type2");
-        assertEquals("type2", t.getType());
-    }
-
-    public void testGeneratePlainText() {
-        assertNull(new TtsMock().generatePlainText());
-    }
-
-    public void testToString() {
-        TtsMock t = new TtsMock();
-        t.setType("a_type");
-        t.setPlainText("a plaintext");
-        t.setParameter("key1", "value1");
-        t.setParameter("aaa", "value2");
-        String str =
-            "type: \"a_type\" " +
-            "plain_text: \"a plaintext\" " +
-            "aaa: \"value2\" " +
-            "key1: \"value1\"";
-        assertEquals(str, t.toString());
-    }
-
-    public void testRemoveParameter() {
-        TtsMock t = new TtsMock();
-        t.setParameter("key1", "value 1");
-        t.setParameter("aaa", "value a");
-        t.removeParameter("key1");
-        String str =
-            "aaa: \"value a\"";
-        assertEquals(str, t.toString());
-    }
-
-    public void testRemoveParameterBySettingNull() {
-        TtsMock t = new TtsMock();
-        t.setParameter("key1", "value 1");
-        t.setParameter("aaa", "value a");
-        t.setParameter("aaa", null);
-        String str =
-            "key1: \"value 1\"";
-        assertEquals(str, t.toString());
-    }
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/MarkupTest.java b/tests/TtsTests/src/com/android/speech/tts/MarkupTest.java
deleted file mode 100644
index 7ef93ce..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/MarkupTest.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import junit.framework.Assert;
-import android.os.Parcel;
-import android.test.InstrumentationTestCase;
-
-import android.speech.tts.Markup;
-
-public class MarkupTest extends InstrumentationTestCase {
-
-  public void testEmptyMarkup() {
-      Markup markup = new Markup();
-      assertNull(markup.getType());
-      assertNull(markup.getPlainText());
-      assertEquals(0, markup.parametersSize());
-      assertEquals(0, markup.nestedMarkupSize());
-  }
-
-  public void testGetSetType() {
-      Markup markup = new Markup();
-      markup.setType("one");
-      assertEquals("one", markup.getType());
-      markup.setType(null);
-      assertNull(markup.getType());
-      markup.setType("two");
-      assertEquals("two", markup.getType());
-  }
-
-  public void testGetSetPlainText() {
-      Markup markup = new Markup();
-      markup.setPlainText("one");
-      assertEquals("one", markup.getPlainText());
-      markup.setPlainText(null);
-      assertNull(markup.getPlainText());
-      markup.setPlainText("two");
-      assertEquals("two", markup.getPlainText());
-  }
-
-  public void testParametersSize1() {
-      Markup markup = new Markup();
-      markup.addNestedMarkup(new Markup());
-      assertEquals(1, markup.nestedMarkupSize());
-  }
-
-  public void testParametersSize2() {
-      Markup markup = new Markup();
-      markup.addNestedMarkup(new Markup());
-      markup.addNestedMarkup(new Markup());
-      assertEquals(2, markup.nestedMarkupSize());
-  }
-
-  public void testRemoveParameter() {
-      Markup m = new Markup("type");
-      m.setParameter("key1", "value1");
-      m.setParameter("key2", "value2");
-      m.setParameter("key3", "value3");
-      assertEquals(3, m.parametersSize());
-      m.removeParameter("key1");
-      assertEquals(2, m.parametersSize());
-      m.removeParameter("key3");
-      assertEquals(1, m.parametersSize());
-      assertNull(m.getParameter("key1"));
-      assertEquals("value2", m.getParameter("key2"));
-      assertNull(m.getParameter("key3"));
-  }
-
-  public void testEmptyEqual() {
-      Markup m1 = new Markup();
-      Markup m2 = new Markup();
-      assertTrue(m1.equals(m2));
-  }
-
-  public void testFilledEqual() {
-      Markup m1 = new Markup();
-      m1.setType("type");
-      m1.setPlainText("plain text");
-      m1.setParameter("key1", "value1");
-      m1.addNestedMarkup(new Markup());
-      Markup m2 = new Markup();
-      m2.setType("type");
-      m2.setPlainText("plain text");
-      m2.setParameter("key1", "value1");
-      m2.addNestedMarkup(new Markup());
-      assertTrue(m1.equals(m2));
-  }
-
-  public void testDifferentTypeEqual() {
-      Markup m1 = new Markup();
-      m1.setType("type1");
-      Markup m2 = new Markup();
-      m2.setType("type2");
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testDifferentPlainTextEqual() {
-      Markup m1 = new Markup();
-      m1.setPlainText("plainText1");
-      Markup m2 = new Markup();
-      m2.setPlainText("plainText2");
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testDifferentParamEqual() {
-      Markup m1 = new Markup();
-      m1.setParameter("test", "value1");
-      Markup m2 = new Markup();
-      m2.setParameter("test", "value2");
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testDifferentParameterKeyEqual() {
-      Markup m1 = new Markup();
-      m1.setParameter("test1", "value");
-      Markup m2 = new Markup();
-      m2.setParameter("test2", "value");
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testDifferentParameterValueEqual() {
-      Markup m1 = new Markup();
-      m1.setParameter("test", "value1");
-      Markup m2 = new Markup();
-      m2.setParameter("test", "value2");
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testDifferentNestedMarkupEqual() {
-      Markup m1 = new Markup();
-      Markup nested = new Markup();
-      nested.setParameter("key", "value");
-      m1.addNestedMarkup(nested);
-      Markup m2 = new Markup();
-      m2.addNestedMarkup(new Markup());
-      assertFalse(m1.equals(m2));
-  }
-
-  public void testEmptyToFromString() {
-      Markup m1 = new Markup();
-      String str = m1.toString();
-      assertEquals("", str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testTypeToFromString() {
-      Markup m1 = new Markup("atype");
-      String str = m1.toString();
-      assertEquals("type: \"atype\"", str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testPlainTextToFromString() {
-      Markup m1 = new Markup();
-      m1.setPlainText("some_plainText");
-      String str = m1.toString();
-      assertEquals("plain_text: \"some_plainText\"", str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testParameterToFromString() {
-      Markup m1 = new Markup("cardinal");
-      m1.setParameter("integer", "-22");
-      String str = m1.toString();
-      assertEquals("type: \"cardinal\" integer: \"-22\"", str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  // Parameters should be ordered alphabettically, so the output is stable.
-  public void testParameterOrderToFromString() {
-      Markup m1 = new Markup("cardinal");
-      m1.setParameter("ccc", "-");
-      m1.setParameter("aaa", "-");
-      m1.setParameter("aa", "-");
-      m1.setParameter("bbb", "-");
-      String str = m1.toString();
-      assertEquals(
-              "type: \"cardinal\" " +
-              "aa: \"-\" " +
-              "aaa: \"-\" " +
-              "bbb: \"-\" " +
-              "ccc: \"-\"",
-              str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testEmptyNestedToFromString() {
-      Markup m1 = new Markup("atype");
-      m1.addNestedMarkup(new Markup());
-      String str = m1.toString();
-      assertEquals("type: \"atype\" markup {}", str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testNestedWithTypeToFromString() {
-      Markup m1 = new Markup("atype");
-      m1.addNestedMarkup(new Markup("nested_type"));
-      String str = m1.toString();
-      assertEquals(
-              "type: \"atype\" " +
-              "markup { type: \"nested_type\" }",
-              str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testRemoveNestedMarkup() {
-      Markup m = new Markup("atype");
-      Markup m1 = new Markup("nested_type1");
-      Markup m2 = new Markup("nested_type2");
-      Markup m3 = new Markup("nested_type3");
-      m.addNestedMarkup(m1);
-      m.addNestedMarkup(m2);
-      m.addNestedMarkup(m3);
-      m.removeNestedMarkup(m1);
-      m.removeNestedMarkup(m3);
-      String str = m.toString();
-      assertEquals(
-              "type: \"atype\" " +
-              "markup { type: \"nested_type2\" }",
-              str);
-      Markup mFromString = Markup.markupFromString(str);
-      assertEquals(m, mFromString);
-  }
-
-  public void testLotsofNestingToFromString() {
-      Markup m1 = new Markup("top")
-          .addNestedMarkup(new Markup("top_child1")
-              .addNestedMarkup(new Markup("top_child1_child1"))
-              .addNestedMarkup(new Markup("top_child1_child2")))
-          .addNestedMarkup(new Markup("top_child2")
-              .addNestedMarkup(new Markup("top_child2_child2"))
-              .addNestedMarkup(new Markup("top_child2_child2")));
-
-      String str = m1.toString();
-      assertEquals(
-              "type: \"top\" " +
-              "markup { " +
-                  "type: \"top_child1\" " +
-                  "markup { type: \"top_child1_child1\" } " +
-                  "markup { type: \"top_child1_child2\" } " +
-              "} " +
-              "markup { " +
-                  "type: \"top_child2\" " +
-                  "markup { type: \"top_child2_child2\" } " +
-                  "markup { type: \"top_child2_child2\" } " +
-              "}",
-              str);
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testFilledToFromString() {
-      Markup m1 = new Markup("measure");
-      m1.setPlainText("fifty-five amps");
-      m1.setParameter("unit", "meter");
-      m1.addNestedMarkup(new Markup("cardinal").setParameter("integer", "55"));
-      String str = m1.toString();
-      assertEquals(
-              "type: \"measure\" " +
-              "plain_text: \"fifty-five amps\" " +
-              "unit: \"meter\" " +
-              "markup { type: \"cardinal\" integer: \"55\" }",
-              str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1, m2);
-  }
-
-  public void testErrorFromString() {
-      String str = "type: \"atype\" markup {mistake}";
-      try {
-          Markup.markupFromString(str);
-          Assert.fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testEscapeQuotes() {
-      Markup m1 = new Markup("text")
-              .setParameter("something_unknown", "\"this\" is \"a sentence \" with quotes\"");
-      String str = m1.toString();
-      assertEquals(
-              "type: \"text\" " +
-              "something_unknown: \"\\\"this\\\" is \\\"a sentence \\\" with quotes\\\"\"",
-              str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1.toString(), m2.toString());
-      assertEquals(m1, m2);
-  }
-
-  public void testEscapeSlashes1() {
-      Markup m1 = new Markup("text")
-              .setParameter("something_unknown", "\\ \\\\ \t \n \"");
-      String str = m1.toString();
-      assertEquals(
-              "type: \"text\" " +
-              "something_unknown: \"\\\\ \\\\\\\\ \t \n \\\"\"",
-              str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1.toString(), m2.toString());
-      assertEquals(m1, m2);
-  }
-
-  public void testEscapeSlashes2() {
-      Markup m1 = new Markup("text")
-              .setParameter("something_unknown", "\\\"\\\"\\\\\"\"\\\\\\\"\"\"");
-      String str = m1.toString();
-      assertEquals(
-              "type: \"text\" " +
-              "something_unknown: \"\\\\\\\"\\\\\\\"\\\\\\\\\\\"\\\"\\\\\\\\\\\\\\\"\\\"\\\"\"",
-              str);
-
-      Markup m2 = Markup.markupFromString(str);
-      assertEquals(m1.toString(), m2.toString());
-      assertEquals(m1, m2);
-  }
-
-  public void testBadInput1() {
-      String str = "type: \"text\" text: \"\\\"";
-      try {
-          Markup.markupFromString(str);
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testBadInput2() {
-      String str = "type: \"text\" text: \"\\a\"";
-      try {
-          Markup.markupFromString(str);
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testValidParameterKey() {
-      Markup m = new Markup();
-      m.setParameter("ke9__yk_88ey_za7_", "test");
-  }
-
-  public void testInValidParameterKeyEmpty() {
-      Markup m = new Markup();
-      try {
-          m.setParameter("", "test");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testInValidParameterKeyDollar() {
-      Markup m = new Markup();
-      try {
-          m.setParameter("ke9y$k88ey7", "test");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testInValidParameterKeySpace() {
-      Markup m = new Markup();
-      try {
-          m.setParameter("ke9yk88ey7 ", "test");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testValidType() {
-      new Markup("_this_is_1_valid_type_222");
-  }
-
-  public void testInValidTypeAmpersand() {
-      try {
-          new Markup("abcde1234&");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testInValidTypeSpace() {
-      try {
-          new Markup(" ");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testSimpleParcelable() {
-      Markup markup = new Markup();
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testTypeParcelable() {
-      Markup markup = new Markup("text");
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testPlainTextsParcelable() {
-      Markup markup = new Markup();
-      markup.setPlainText("plainText");
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testParametersParcelable() {
-      Markup markup = new Markup();
-      markup.setParameter("key1", "value1");
-      markup.setParameter("key2", "value2");
-      markup.setParameter("key3", "value3");
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testNestedParcelable() {
-      Markup markup = new Markup();
-      markup.addNestedMarkup(new Markup("first"));
-      markup.addNestedMarkup(new Markup("second"));
-      markup.addNestedMarkup(new Markup("third"));
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testAllFieldsParcelable() {
-      Markup markup = new Markup("text");
-      markup.setPlainText("plain text");
-      markup.setParameter("key1", "value1");
-      markup.setParameter("key2", "value2");
-      markup.setParameter("key3", "value3");
-      markup.addNestedMarkup(new Markup("first"));
-      markup.addNestedMarkup(new Markup("second"));
-      markup.addNestedMarkup(new Markup("third"));
-
-      Parcel parcel = Parcel.obtain();
-      markup.writeToParcel(parcel, 0);
-      parcel.setDataPosition(0);
-
-      Markup fromParcel = (Markup) Markup.CREATOR.createFromParcel(parcel);
-
-      assertFalse(markup == fromParcel);
-      assertEquals(markup, fromParcel);
-  }
-
-  public void testKeyCannotBeType() {
-      try {
-          new Markup().setParameter("type", "vale");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-
-  public void testKeyCannotBePlainText() {
-      try {
-          new Markup().setParameter("plain_text", "value");
-          fail("Expected IllegalArgumentException");
-      } catch (IllegalArgumentException e) {}
-  }
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsCardinalTest.java b/tests/TtsTests/src/com/android/speech/tts/TtsCardinalTest.java
deleted file mode 100644
index c34f4ac..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/TtsCardinalTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import junit.framework.Assert;
-import android.test.InstrumentationTestCase;
-import android.test.MoreAsserts;
-
-import android.speech.tts.Markup;
-import android.speech.tts.Utterance;
-import android.speech.tts.Utterance.TtsCardinal;
-import android.speech.tts.Utterance.TtsText;
-
-public class TtsCardinalTest extends InstrumentationTestCase {
-
-    public void testConstruct() {
-        assertNotNull(new TtsCardinal(0));
-    }
-
-    public void testFluentAPI() {
-        new TtsCardinal()
-            .setPlainText("a plaintext") // from AbstractTts
-            .setGender(Utterance.GENDER_MALE) // from AbstractTtsSemioticClass
-            .setInteger("-10001"); // from TtsText
-    }
-
-    public void testZero() {
-        assertEquals("0", new TtsCardinal(0).getInteger());
-    }
-
-    public void testThirtyOne() {
-        assertEquals("31", new TtsCardinal(31).getInteger());
-    }
-
-    public void testMarkupZero() {
-        TtsCardinal c = new TtsCardinal(0);
-        Markup m = c.getMarkup();
-        assertEquals("0", m.getParameter("integer"));
-    }
-
-    public void testMarkupThirtyOne() {
-        TtsCardinal c = new TtsCardinal(31);
-        Markup m = c.getMarkup();
-        assertEquals("31", m.getParameter("integer"));
-    }
-
-    public void testMarkupThirtyOneString() {
-        TtsCardinal c = new TtsCardinal("31");
-        Markup m = c.getMarkup();
-        assertEquals("31", m.getParameter("integer"));
-    }
-
-    public void testMarkupNegativeThirtyOne() {
-        TtsCardinal c = new TtsCardinal(-31);
-        Markup m = c.getMarkup();
-        assertEquals("-31", m.getParameter("integer"));
-    }
-
-    public void testMarkupMinusZero() {
-        TtsCardinal c = new TtsCardinal("-0");
-        Markup m = c.getMarkup();
-        assertEquals("-0", m.getParameter("integer"));
-    }
-
-    public void testMarkupNegativeThirtyOneString() {
-        TtsCardinal c = new TtsCardinal("-31");
-        Markup m = c.getMarkup();
-        assertEquals("-31", m.getParameter("integer"));
-    }
-
-    public void testOnlyLetters() {
-        try {
-            new TtsCardinal("abc");
-            Assert.fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testOnlyMinus() {
-        try {
-            new TtsCardinal("-");
-            Assert.fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testNegativeLetters() {
-        try {
-            new TtsCardinal("-abc");
-            Assert.fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testLetterNumberMix() {
-        try {
-            new TtsCardinal("-0a1b2c");
-            Assert.fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void letterNumberMix2() {
-        try {
-            new TtsCardinal("-a0b1c2");
-            Assert.fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsTextTest.java b/tests/TtsTests/src/com/android/speech/tts/TtsTextTest.java
deleted file mode 100644
index 35fd453..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/TtsTextTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import android.test.InstrumentationTestCase;
-
-import android.speech.tts.Markup;
-import android.speech.tts.Utterance;
-import android.speech.tts.Utterance.TtsText;
-
-public class TtsTextTest extends InstrumentationTestCase {
-
-    public void testConstruct() {
-        assertNotNull(new TtsText());
-    }
-
-    public void testFluentAPI() {
-        new TtsText()
-            .setPlainText("a plaintext") // from AbstractTts
-            .setGender(Utterance.GENDER_MALE) // from AbstractTtsSemioticClass
-            .setText("text"); // from TtsText
-    }
-
-    public void testConstructEmptyString() {
-        assertTrue(new TtsText("").getText().isEmpty());
-    }
-
-    public void testConstructString() {
-        assertEquals("this is a test.", new TtsText("this is a test.").getText());
-    }
-
-    public void testSetText() {
-        assertEquals("This is a test.", new TtsText().setText("This is a test.").getText());
-    }
-
-    public void testEmptyMarkup() {
-        TtsText t = new TtsText();
-        Markup m = t.getMarkup();
-        assertEquals("text", m.getType());
-        assertNull(m.getPlainText());
-        assertEquals(0, m.nestedMarkupSize());
-    }
-
-    public void testConstructStringMarkup() {
-        TtsText t = new TtsText("test");
-        Markup m = t.getMarkup();
-        assertEquals("text", m.getType());
-        assertEquals("test", m.getParameter("text"));
-        assertEquals(0, m.nestedMarkupSize());
-    }
-
-    public void testSetStringMarkup() {
-        TtsText t = new TtsText();
-        t.setText("test");
-        Markup m = t.getMarkup();
-        assertEquals("text", m.getType());
-        assertEquals("test", m.getParameter("text"));
-        assertEquals(0, m.nestedMarkupSize());
-    }
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/UtteranceTest.java b/tests/TtsTests/src/com/android/speech/tts/UtteranceTest.java
deleted file mode 100644
index 8014dd1..0000000
--- a/tests/TtsTests/src/com/android/speech/tts/UtteranceTest.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.speech.tts;
-
-import android.speech.tts.Markup;
-import android.speech.tts.Utterance;
-import android.speech.tts.Utterance.TtsCardinal;
-import android.speech.tts.Utterance.TtsText;
-
-import android.test.InstrumentationTestCase;
-
-public class UtteranceTest extends InstrumentationTestCase {
-
-    public void testEmptyUtterance() {
-        Utterance utt = new Utterance();
-        assertEquals(0, utt.size());
-    }
-
-    public void testSizeCardinal() {
-        Utterance utt = new Utterance()
-                .append(new TtsCardinal(42));
-        assertEquals(1, utt.size());
-    }
-
-    public void testSizeCardinalString() {
-        Utterance utt = new Utterance()
-                .append(new TtsCardinal(42))
-                .append(new TtsText("is the answer"));
-        assertEquals(2, utt.size());
-    }
-
-    public void testMarkupEmpty() {
-        Markup m = new Utterance().createMarkup();
-        assertEquals("utterance", m.getType());
-        assertEquals("", m.getPlainText());
-    }
-
-    public void testMarkupCardinal() {
-        Utterance utt = new Utterance()
-                .append(new TtsCardinal(42));
-        Markup markup = utt.createMarkup();
-        assertEquals("utterance", markup.getType());
-        assertEquals("42", markup.getPlainText());
-        assertEquals("42", markup.getNestedMarkup(0).getParameter("integer"));
-        assertEquals("42", markup.getNestedMarkup(0).getPlainText());
-    }
-
-    public void testMarkupCardinalString() {
-        Utterance utt = new Utterance()
-                .append(new TtsCardinal(42))
-                .append(new TtsText("is not just a number."));
-        Markup markup = utt.createMarkup();
-        assertEquals("utterance", markup.getType());
-        assertEquals("42 is not just a number.", markup.getPlainText());
-        assertEquals("cardinal", markup.getNestedMarkup(0).getType());
-        assertEquals("42", markup.getNestedMarkup(0).getParameter("integer"));
-        assertEquals("42", markup.getNestedMarkup(0).getPlainText());
-        assertEquals("text", markup.getNestedMarkup(1).getType());
-        assertEquals("is not just a number.", markup.getNestedMarkup(1).getParameter("text"));
-        assertEquals("is not just a number.", markup.getNestedMarkup(1).getPlainText());
-    }
-
-    public void testTextCardinalToFromString() {
-        Utterance utt = new Utterance()
-                .append(new TtsCardinal(55))
-                .append(new TtsText("this is a text."));
-        String str = utt.toString();
-        assertEquals(
-            "type: \"utterance\" " +
-            "markup { " +
-                "type: \"cardinal\" " +
-                "integer: \"55\" " +
-            "} " +
-            "markup { " +
-                "type: \"text\" " +
-                "text: \"this is a text.\" " +
-            "}"
-            , str);
-
-        Utterance utt_new = Utterance.utteranceFromString(str);
-        assertEquals(str, utt_new.toString());
-    }
-
-    public void testNotUtteranceFromString() {
-        String str =
-            "type: \"this_is_not_an_utterance\" " +
-            "markup { " +
-                "type: \"cardinal\" " +
-                "plain_text: \"55\" " +
-                "integer: \"55\" " +
-            "}";
-        try {
-            Utterance.utteranceFromString(str);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testFromMarkup() {
-        String markup_str =
-            "type: \"utterance\" " +
-            "markup { " +
-                "type: \"cardinal\" " +
-                "plain_text: \"55\" " +
-                "integer: \"55\" " +
-            "} " +
-            "markup { " +
-                "type: \"text\" " +
-                "plain_text: \"this is a text.\" " +
-                "text: \"this is a text.\" " +
-            "}";
-        Utterance utt = Utterance.utteranceFromString(markup_str);
-        assertEquals(markup_str, utt.toString());
-    }
-
-    public void testsetPlainText() {
-        Utterance utt = new Utterance()
-            .append(new TtsCardinal(-100).setPlainText("minus one hundred"));
-        assertEquals("minus one hundred", utt.get(0).getPlainText());
-    }
-
-    public void testRemoveTextThroughSet() {
-        Utterance utt = new Utterance()
-            .append(new TtsText().setText("test").setText(null));
-        assertNull(((TtsText) utt.get(0)).getText());
-    }
-
-    public void testUnknownNodeWithPlainText() {
-        String str =
-            "type: \"utterance\" " +
-            "markup { " +
-                "type: \"some_future_feature\" " +
-                "plain_text: \"biep bob bob\" " +
-                "bombom: \"lorum ipsum\" " +
-            "}";
-        Utterance utt = Utterance.utteranceFromString(str);
-        assertNotNull(utt);
-        assertEquals("text", utt.get(0).getType());
-        assertEquals("biep bob bob", ((TtsText) utt.get(0)).getText());
-    }
-
-    public void testUnknownNodeWithNoPlainTexts() {
-        String str =
-            "type: \"utterance\" " +
-            "markup { " +
-                "type: \"some_future_feature\" " +
-                "bombom: \"lorum ipsum\" " +
-                "markup { type: \"cardinal\" integer: \"10\" } " +
-                "markup { type: \"text\" text: \"pears\" } " +
-            "}";
-        Utterance utt = Utterance.utteranceFromString(str);
-        assertEquals(
-            "type: \"utterance\" " +
-            "markup { type: \"cardinal\" integer: \"10\" } " +
-            "markup { type: \"text\" text: \"pears\" }", utt.toString());
-    }
-
-    public void testCreateWarningOnFallbackTrue() {
-        Utterance utt = new Utterance()
-          .append(new TtsText("test"))
-          .setNoWarningOnFallback(true);
-        assertEquals(
-            "type: \"utterance\" " +
-            "no_warning_on_fallback: \"true\" " +
-            "markup { " +
-                "type: \"text\" " +
-                "text: \"test\" " +
-            "}", utt.toString());
-    }
-
-    public void testCreateWarningOnFallbackFalse() {
-        Utterance utt = new Utterance()
-          .append(new TtsText("test"))
-          .setNoWarningOnFallback(false);
-        assertEquals(
-            "type: \"utterance\" " +
-            "no_warning_on_fallback: \"false\" " +
-            "markup { " +
-                "type: \"text\" " +
-                "text: \"test\" " +
-            "}", utt.toString());
-    }
-
-    public void testCreatePlainTexts() {
-        Utterance utt = new Utterance()
-            .append(new TtsText("test"))
-            .append(new TtsCardinal(-55));
-        assertEquals(
-            "type: \"utterance\" " +
-            "plain_text: \"test -55\" " +
-            "markup { type: \"text\" plain_text: \"test\" text: \"test\" } " +
-            "markup { type: \"cardinal\" plain_text: \"-55\" integer: \"-55\" }",
-            utt.createMarkup().toString()
-        );
-    }
-
-    public void testDontOverwritePlainTexts() {
-        Utterance utt = new Utterance()
-            .append(new TtsText("test").setPlainText("else"))
-            .append(new TtsCardinal(-55).setPlainText("44"));
-        assertEquals(
-            "type: \"utterance\" " +
-            "plain_text: \"else 44\" " +
-            "markup { type: \"text\" plain_text: \"else\" text: \"test\" } " +
-            "markup { type: \"cardinal\" plain_text: \"44\" integer: \"-55\" }",
-            utt.createMarkup().toString()
-        );
-    }
-
-    public void test99BottlesOnWallMarkup() {
-        Utterance utt = new Utterance()
-            .append("there are")
-            .append(99)
-            .append("bottles on the wall.");
-        assertEquals(
-                "type: \"utterance\" " +
-                "plain_text: \"there are 99 bottles on the wall.\" " +
-                "markup { type: \"text\" plain_text: \"there are\" text: \"there are\" } " +
-                "markup { type: \"cardinal\" plain_text: \"99\" integer: \"99\" } " +
-                "markup { type: \"text\" plain_text: \"bottles on the wall.\" text: \"bottles on the wall.\" }",
-                utt.createMarkup().toString());
-        assertEquals("99", utt.createMarkup().getNestedMarkup(1).getPlainText());
-        Markup markup = new Markup(utt.createMarkup());
-        assertEquals("99", markup.getNestedMarkup(1).getPlainText());
-    }
-
-    public void testWhat() {
-        Utterance utt = new Utterance()
-            .append("there are")
-            .append(99)
-            .append("bottles on the wall.");
-        Markup m = utt.createMarkup();
-        m.getNestedMarkup(1).getPlainText().equals("99");
-    }
-}