Merge "Add IN/OUT flag for all Visibility transitions."
diff --git a/Android.mk b/Android.mk
index efbee5e..bb65398 100644
--- a/Android.mk
+++ b/Android.mk
@@ -832,7 +832,6 @@
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
 		-toroot / \
 		-hdf android.whichdoc online \
-		-briefdocs \
 		$(sample_groups) \
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
diff --git a/api/current.txt b/api/current.txt
index 3878d3e..84c4f53 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12518,6 +12518,7 @@
     field public static final int CONTROL_SCENE_MODE_DISABLED = 0; // 0x0
     field public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1; // 0x1
     field public static final int CONTROL_SCENE_MODE_FIREWORKS = 12; // 0xc
+    field public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17; // 0x11
     field public static final int CONTROL_SCENE_MODE_LANDSCAPE = 4; // 0x4
     field public static final int CONTROL_SCENE_MODE_NIGHT = 5; // 0x5
     field public static final int CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6; // 0x6
@@ -27663,14 +27664,14 @@
 
   public abstract class Connection {
     ctor protected Connection();
-    method public final void conference();
     method public final android.telecomm.CallAudioState getCallAudioState();
-    method public java.util.List<android.telecomm.Connection> getChildConnections();
+    method public final java.util.List<android.telecomm.Connection> getChildConnections();
     method public final android.net.Uri getHandle();
-    method public android.telecomm.Connection getParentConnection();
-    method public boolean isConferenceCapable();
-    method public boolean isConferenceConnection();
-    method public boolean isRequestingRingback();
+    method public final android.telecomm.Connection getParentConnection();
+    method public final int getState();
+    method public final boolean isConferenceCapable();
+    method public final boolean isConferenceConnection();
+    method public final boolean isRequestingRingback();
     method protected void onAbort();
     method protected void onAnswer();
     method protected void onChildrenChanged(java.util.List<android.telecomm.Connection>);
@@ -27682,21 +27683,20 @@
     method protected void onReject();
     method protected void onSeparate();
     method protected void onSetAudioState(android.telecomm.CallAudioState);
-    method protected void onSetSignal(android.os.Bundle);
     method protected void onSetState(int);
     method protected void onStopDtmfTone();
     method protected void onUnhold();
-    method protected void setActive();
-    method public void setAudioState(android.telecomm.CallAudioState);
-    method protected void setDestroyed();
-    method protected void setDialing();
-    method protected void setDisconnected(int, java.lang.String);
-    method protected void setHandle(android.net.Uri);
-    method protected void setIsConferenceCapable(boolean);
-    method protected void setOnHold();
-    method public void setParentConnection(android.telecomm.Connection);
-    method protected void setRequestingRingback(boolean);
-    method protected void setRinging();
+    method public final void setActive();
+    method public final void setDestroyed();
+    method public final void setDialing();
+    method public final void setDisconnected(int, java.lang.String);
+    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 setRequestingRingback(boolean);
+    method public final void setRinging();
+    method public final void setSignal(android.os.Bundle);
     method public static java.lang.String stateToString(int);
   }
 
@@ -34844,7 +34844,7 @@
     ctor public CursorAnchorInfo(android.os.Parcel);
     method public int describeContents();
     method public android.graphics.RectF getCharacterRect(int);
-    method public java.lang.String getComposingText();
+    method public java.lang.CharSequence getComposingText();
     method public int getComposingTextStart();
     method public float getInsertionMarkerBaseline();
     method public float getInsertionMarkerBottom();
@@ -35271,6 +35271,7 @@
 
   public class CookieManager {
     method public synchronized boolean acceptCookie();
+    method public synchronized boolean acceptThirdPartyCookies(android.webkit.WebView);
     method public static boolean allowFileSchemeCookies();
     method public java.lang.String getCookie(java.lang.String);
     method public static synchronized android.webkit.CookieManager getInstance();
@@ -35282,6 +35283,7 @@
     method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
     method public synchronized void setAcceptCookie(boolean);
     method public static void setAcceptFileSchemeCookies(boolean);
+    method public synchronized void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
     method public void setCookie(java.lang.String, java.lang.String);
     method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
   }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 88746bf4..87140a3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -538,6 +538,30 @@
         }
 
         /**
+         * Sets the label for this task description.
+         * @hide
+         */
+        public void setLabel(String label) {
+            mLabel = label;
+        }
+
+        /**
+         * Sets the primary color for this task description.
+         * @hide
+         */
+        public void setPrimaryColor(int primaryColor) {
+            mColorPrimary = primaryColor;
+        }
+
+        /**
+         * Sets the icon for this task description.
+         * @hide
+         */
+        public void setIcon(Bitmap icon) {
+            mIcon = icon;
+        }
+
+        /**
          * @return The label and description of the current state of this task.
          */
         public String getLabel() {
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 554df3e..252e3d2 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -640,7 +640,7 @@
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
      *
      * @param device Remote Bluetooth Device
-     * @param data Data to send
+     * @param report Report to send
      * @return false on immediate error,
      *               true otherwise
      * @hide
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
deleted file mode 100644
index f0c8299..0000000
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.bluetooth;
-
-import android.net.BaseNetworkStateTracker;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.DhcpResults;
-import android.net.NetworkCapabilities;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkStateTracker;
-import android.net.NetworkUtils;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.util.AsyncChannel;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * This class tracks the data connection associated with Bluetooth
- * reverse tethering. This is a singleton class and an instance will be
- * created by ConnectivityService. BluetoothService will call into this
- * when a reverse tethered connection needs to be activated.
- *
- * @hide
- */
-public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
-    private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
-    private static final String TAG = "BluetoothTethering";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = true;
-
-    // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
-    private static final int EVENT_NETWORK_FAILED = 1;
-
-    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
-    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
-    private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
-    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
-
-    private final Object mLinkPropertiesLock = new Object();
-    private final Object mNetworkInfoLock = new Object();
-
-    private BluetoothPan mBluetoothPan;
-    private static String mRevTetheredIface;
-    /* For sending events to connectivity service handler */
-    private Handler mCsHandler;
-    private static BluetoothTetheringDataTracker sInstance;
-    private BtdtHandler mBtdtHandler;
-    private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);
-
-    private BluetoothTetheringDataTracker() {
-        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
-        mLinkProperties = new LinkProperties();
-        mNetworkCapabilities = new NetworkCapabilities();
-
-        mNetworkInfo.setIsAvailable(false);
-        setTeardownRequested(false);
-    }
-
-    public static synchronized BluetoothTetheringDataTracker getInstance() {
-        if (sInstance == null) sInstance = new BluetoothTetheringDataTracker();
-        return sInstance;
-    }
-
-    public Object Clone() throws CloneNotSupportedException {
-        throw new CloneNotSupportedException();
-    }
-
-    public void setTeardownRequested(boolean isRequested) {
-        mTeardownRequested.set(isRequested);
-    }
-
-    public boolean isTeardownRequested() {
-        return mTeardownRequested.get();
-    }
-
-    /**
-     * Begin monitoring connectivity
-     */
-    public void startMonitoring(Context context, Handler target) {
-        if (DBG) Log.d(TAG, "startMonitoring: target: " + target);
-        mContext = context;
-        mCsHandler = target;
-        if (VDBG) Log.d(TAG, "startMonitoring: mCsHandler: " + mCsHandler);
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
-        }
-        mBtdtHandler = new BtdtHandler(target.getLooper(), this);
-    }
-
-    private BluetoothProfile.ServiceListener mProfileServiceListener =
-        new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mBluetoothPan = (BluetoothPan) proxy;
-        }
-        public void onServiceDisconnected(int profile) {
-            mBluetoothPan = null;
-        }
-    };
-
-    /**
-     * Disable connectivity to a network
-     * TODO: do away with return value after making MobileDataStateTracker async
-     */
-    public boolean teardown() {
-        mTeardownRequested.set(true);
-        if (mBluetoothPan != null) {
-            for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
-                mBluetoothPan.disconnect(device);
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
-        // not implemented
-    }
-
-    /**
-     * Re-enable connectivity to a network after a {@link #teardown()}.
-     */
-    public boolean reconnect() {
-        mTeardownRequested.set(false);
-        //Ignore
-        return true;
-    }
-
-    /**
-     * Turn the wireless radio off for a network.
-     * @param turnOn {@code true} to turn the radio on, {@code false}
-     */
-    public boolean setRadio(boolean turnOn) {
-        return true;
-    }
-
-    /**
-     * @return true - If are we currently tethered with another device.
-     */
-    public synchronized boolean isAvailable() {
-        return mNetworkInfo.isAvailable();
-    }
-
-    /**
-     * Tells the underlying networking system that the caller wants to
-     * begin using the named feature. The interpretation of {@code feature}
-     * is completely up to each networking implementation.
-     * @param feature the name of the feature to be used
-     * @param callingPid the process ID of the process that is issuing this request
-     * @param callingUid the user ID of the process that is issuing this request
-     * @return an integer value representing the outcome of the request.
-     * The interpretation of this value is specific to each networking
-     * implementation+feature combination, except that the value {@code -1}
-     * always indicates failure.
-     * TODO: needs to go away
-     */
-    public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
-        return -1;
-    }
-
-    /**
-     * Tells the underlying networking system that the caller is finished
-     * using the named feature. The interpretation of {@code feature}
-     * is completely up to each networking implementation.
-     * @param feature the name of the feature that is no longer needed.
-     * @param callingPid the process ID of the process that is issuing this request
-     * @param callingUid the user ID of the process that is issuing this request
-     * @return an integer value representing the outcome of the request.
-     * The interpretation of this value is specific to each networking
-     * implementation+feature combination, except that the value {@code -1}
-     * always indicates failure.
-     * TODO: needs to go away
-     */
-    public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
-        return -1;
-    }
-
-    @Override
-    public void setUserDataEnable(boolean enabled) {
-        Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
-    }
-
-    @Override
-    public void setPolicyDataEnable(boolean enabled) {
-        Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
-    }
-
-    /**
-     * Check if private DNS route is set for the network
-     */
-    public boolean isPrivateDnsRouteSet() {
-        return mPrivateDnsRouteSet.get();
-    }
-
-    /**
-     * Set a flag indicating private DNS route is set
-     */
-    public void privateDnsRouteSet(boolean enabled) {
-        mPrivateDnsRouteSet.set(enabled);
-    }
-
-    /**
-     * Fetch NetworkInfo for the network
-     */
-    public NetworkInfo getNetworkInfo() {
-        synchronized (mNetworkInfoLock) {
-            return new NetworkInfo(mNetworkInfo);
-        }
-    }
-
-    /**
-     * Fetch LinkProperties for the network
-     */
-    public LinkProperties getLinkProperties() {
-        synchronized (mLinkPropertiesLock) {
-            return new LinkProperties(mLinkProperties);
-        }
-    }
-
-    /**
-     * Fetch default gateway address for the network
-     */
-    public int getDefaultGatewayAddr() {
-        return mDefaultGatewayAddr.get();
-    }
-
-    /**
-     * Check if default route is set
-     */
-    public boolean isDefaultRouteSet() {
-        return mDefaultRouteSet.get();
-    }
-
-    /**
-     * Set a flag indicating default route is set for the network
-     */
-    public void defaultRouteSet(boolean enabled) {
-        mDefaultRouteSet.set(enabled);
-    }
-
-    /**
-     * Return the system properties name associated with the tcp buffer sizes
-     * for this network.
-     */
-    public String getTcpBufferSizesPropName() {
-        return "net.tcp.buffersize.wifi";
-    }
-
-    private static short countPrefixLength(byte [] mask) {
-        short count = 0;
-        for (byte b : mask) {
-            for (int i = 0; i < 8; ++i) {
-                if ((b & (1 << i)) != 0) {
-                    ++count;
-                }
-            }
-        }
-        return count;
-    }
-
-    void startReverseTether(final LinkProperties linkProperties) {
-        if (linkProperties == null || TextUtils.isEmpty(linkProperties.getInterfaceName())) {
-            Log.e(TAG, "attempted to reverse tether with empty interface");
-            return;
-        }
-        synchronized (mLinkPropertiesLock) {
-            if (mLinkProperties.getInterfaceName() != null) {
-                Log.e(TAG, "attempted to reverse tether while already in process");
-                return;
-            }
-            mLinkProperties = linkProperties;
-        }
-        Thread dhcpThread = new Thread(new Runnable() {
-            public void run() {
-                //Currently this thread runs independently.
-                DhcpResults dhcpResults = new DhcpResults();
-                boolean success = NetworkUtils.runDhcp(linkProperties.getInterfaceName(),
-                        dhcpResults);
-                synchronized (mLinkPropertiesLock) {
-                    if (linkProperties.getInterfaceName() != mLinkProperties.getInterfaceName()) {
-                        Log.e(TAG, "obsolete DHCP run aborted");
-                        return;
-                    }
-                    if (!success) {
-                        Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
-                        mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
-                        return;
-                    }
-                    mLinkProperties = dhcpResults.linkProperties;
-                    synchronized (mNetworkInfoLock) {
-                        mNetworkInfo.setIsAvailable(true);
-                        mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-                        if (mCsHandler != null) {
-                            Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
-                                    new NetworkInfo(mNetworkInfo));
-                            msg.sendToTarget();
-                       }
-                    }
-                    return;
-                }
-            }
-        });
-        dhcpThread.start();
-    }
-
-    void stopReverseTether() {
-        synchronized (mLinkPropertiesLock) {
-            if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
-                Log.e(TAG, "attempted to stop reverse tether with nothing tethered");
-                return;
-            }
-            NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
-            mLinkProperties.clear();
-            synchronized (mNetworkInfoLock) {
-                mNetworkInfo.setIsAvailable(false);
-                mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-
-                if (mCsHandler != null) {
-                    mCsHandler.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)).
-                            sendToTarget();
-                }
-            }
-        }
-    }
-
-    public void setDependencyMet(boolean met) {
-        // not supported on this network
-    }
-
-    @Override
-    public void addStackedLink(LinkProperties link) {
-        mLinkProperties.addStackedLink(link);
-    }
-
-    @Override
-    public void removeStackedLink(LinkProperties link) {
-        mLinkProperties.removeStackedLink(link);
-    }
-
-    static class BtdtHandler extends Handler {
-        private AsyncChannel mStackChannel;
-        private final BluetoothTetheringDataTracker mBtdt;
-
-        BtdtHandler(Looper looper, BluetoothTetheringDataTracker parent) {
-            super(looper);
-            mBtdt = parent;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_HALF_CONNECTED");
-                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        AsyncChannel ac = (AsyncChannel)msg.obj;
-                        if (mBtdt.mAsyncChannel.compareAndSet(null, ac) == false) {
-                            Log.e(TAG, "Trying to set mAsyncChannel twice!");
-                        } else {
-                            ac.sendMessage(
-                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
-                        }
-                    }
-                    break;
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_DISCONNECTED");
-                    mBtdt.stopReverseTether();
-                    mBtdt.mAsyncChannel.set(null);
-                    break;
-                case NetworkStateTracker.EVENT_NETWORK_CONNECTED:
-                    LinkProperties linkProperties = (LinkProperties)(msg.obj);
-                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_CONNECTED, " + linkProperties);
-                    mBtdt.startReverseTether(linkProperties);
-                    break;
-                case NetworkStateTracker.EVENT_NETWORK_DISCONNECTED:
-                    linkProperties = (LinkProperties)(msg.obj);
-                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
-                    mBtdt.stopReverseTether();
-                    break;
-                case EVENT_NETWORK_FAILED:
-                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
-                    mBtdt.teardown();
-                    break;
-            }
-        }
-    }
-
-    @Override
-    public void supplyMessenger(Messenger messenger) {
-        if (messenger != null) {
-            new AsyncChannel().connect(mContext, mBtdtHandler, messenger);
-        }
-    }
-}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index ef8c67b..14e6f92 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -466,6 +466,34 @@
             new Key<Integer>("android.control.maxRegionsAf", int.class);
 
     /**
+     * <p>List of available high speed video size and fps range configurations
+     * supported by the camera device, in the format of (width, height, fps_min, fps_max).</p>
+     * <p>When HIGH_SPEED_VIDEO is supported in {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes},
+     * this metadata will list the supported high speed video size and fps range
+     * configurations. All the sizes listed in this configuration will be a subset
+     * of the sizes reported by StreamConfigurationMap#getOutputSizes for processed
+     * non-stalling formats.</p>
+     * <p>For the high speed video use case, where the application will set
+     * {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} to HIGH_SPEED_VIDEO in capture requests, the application must
+     * select the video size and fps range from this metadata to configure the recording and
+     * preview streams and setup the recording requests. For example, if the application intends
+     * to do high speed recording, it can select the maximum size reported by this metadata to
+     * configure output streams. Once the size is selected, application can filter this metadata
+     * by selected size and get the supported fps ranges, and use these fps ranges to setup the
+     * recording requests.</p>
+     * <p>For normal video recording use case, where some application will NOT set
+     * {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} to HIGH_SPEED_VIDEO in capture requests, the fps ranges
+     * reported in this metadata must not be used to setup capture requests, or it will cause
+     * request error.</p>
+     *
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     * @hide
+     */
+    public static final Key<int[]> CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS =
+            new Key<int[]>("android.control.availableHighSpeedVideoConfigurations", int[].class);
+
+    /**
      * <p>The set of edge enhancement modes supported by this camera device.</p>
      * <p>This tag lists the valid modes for {@link CaptureRequest#EDGE_MODE android.edge.mode}.</p>
      * <p>Full-capability camera devices must always support OFF and FAST.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 889b127..e464f2a 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1393,6 +1393,84 @@
      */
     public static final int CONTROL_SCENE_MODE_BARCODE = 16;
 
+    /**
+     * <p>Optimized for high speed video recording (frame rate &gt;=60fps) use case.</p>
+     * <p>The supported high speed video sizes and fps ranges are specified in
+     * android.control.availableHighSpeedVideoConfigurations. To get desired
+     * output frame rates, the application is only allowed to select video size
+     * and fps range combinations listed in this static metadata. The fps range
+     * can be control via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p>
+     * <p>In this mode, the camera device will override aeMode, awbMode, and afMode to
+     * ON, ON, and CONTINUOUS_VIDEO, respectively. All post-processing block mode
+     * controls will be overridden to be FAST. Therefore, no manual control of capture
+     * and post-processing parameters is possible. All other controls operate the
+     * same as when {@link CaptureRequest#CONTROL_MODE android.control.mode} == AUTO. This means that all other
+     * android.control.* fields continue to work, such as</p>
+     * <ul>
+     * <li>{@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}</li>
+     * <li>{@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation}</li>
+     * <li>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</li>
+     * <li>{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</li>
+     * <li>{@link CaptureRequest#CONTROL_EFFECT_MODE android.control.effectMode}</li>
+     * <li>{@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}</li>
+     * <li>{@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}</li>
+     * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li>
+     * <li>{@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}</li>
+     * <li>{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}</li>
+     * </ul>
+     * <p>Outside of android.control.*, the following controls will work:</p>
+     * <ul>
+     * <li>{@link CaptureRequest#FLASH_MODE android.flash.mode} (automatic flash for still capture will not work since aeMode is ON)</li>
+     * <li>{@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode} (if it is supported)</li>
+     * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li>
+     * <li>{@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode}</li>
+     * </ul>
+     * <p>For high speed recording use case, the actual maximum supported frame rate may
+     * be lower than what camera can output, depending on the destination Surfaces for
+     * the image data. For example, if the destination surface is from video encoder,
+     * the application need check if the video encoder is capable of supporting the
+     * high frame rate for a given video size, or it will end up with lower recording
+     * frame rate. If the destination surface is from preview window, the preview frame
+     * rate will be bounded by the screen refresh rate.</p>
+     * <p>The camera device will only support up to 2 output high speed streams
+     * (processed non-stalling format defined in android.request.maxNumOutputStreams)
+     * in this mode. This control will be effective only if all of below conditions are true:</p>
+     * <ul>
+     * <li>The application created no more than maxNumHighSpeedStreams processed non-stalling
+     * format output streams, where maxNumHighSpeedStreams is calculated as
+     * min(2, android.request.maxNumOutputStreams[Processed (but not-stalling)]).</li>
+     * <li>The stream sizes are selected from the sizes reported by
+     * android.control.availableHighSpeedVideoConfigurations.</li>
+     * <li>No processed non-stalling or raw streams are configured.</li>
+     * </ul>
+     * <p>When above conditions are NOT satistied, the controls of this mode and
+     * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange} will be ignored by the camera device,
+     * the camera device will fall back to {@link CaptureRequest#CONTROL_MODE android.control.mode} <code>==</code> AUTO,
+     * and the returned capture result metadata will give the fps range choosen
+     * by the camera device.</p>
+     * <p>Switching into or out of this mode may trigger some camera ISP/sensor
+     * reconfigurations, which may introduce extra latency. It is recommended that
+     * the application avoids unnecessary scene mode switch as much as possible.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
+     * @see CaptureRequest#CONTROL_AF_REGIONS
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
+     * @see CaptureRequest#CONTROL_AWB_LOCK
+     * @see CaptureRequest#CONTROL_AWB_REGIONS
+     * @see CaptureRequest#CONTROL_EFFECT_MODE
+     * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureRequest#FLASH_MODE
+     * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
+     * @see CaptureRequest#SCALER_CROP_REGION
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     * @see CaptureRequest#CONTROL_SCENE_MODE
+     */
+    public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
     //
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5bc59dc..91ff7fa 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1011,6 +1011,7 @@
      * @see #CONTROL_SCENE_MODE_PARTY
      * @see #CONTROL_SCENE_MODE_CANDLELIGHT
      * @see #CONTROL_SCENE_MODE_BARCODE
+     * @see #CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO
      */
     public static final Key<Integer> CONTROL_SCENE_MODE =
             new Key<Integer>("android.control.sceneMode", int.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9097220..be2d960 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1581,6 +1581,7 @@
      * @see #CONTROL_SCENE_MODE_PARTY
      * @see #CONTROL_SCENE_MODE_CANDLELIGHT
      * @see #CONTROL_SCENE_MODE_BARCODE
+     * @see #CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO
      */
     public static final Key<Integer> CONTROL_SCENE_MODE =
             new Key<Integer>("android.control.sceneMode", int.class);
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 1646120..4797e20 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -346,6 +346,14 @@
     }
 
     private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
+        /*
+         * android.control.maxRegions
+         */
+        int[] maxRegions = new int[3];
+        maxRegions[0] = p.getMaxNumMeteringAreas();
+        maxRegions[1] = 0; // AWB regions not supported in API1
+        maxRegions[2] = p.getMaxNumFocusAreas();
+        m.set(CONTROL_MAX_REGIONS, maxRegions);
         // TODO
     }
 
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index d86dd5e..c87b674 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -101,6 +101,9 @@
     /** Logical address used to indicate it is not initialized or invalid. */
     public static final int ADDR_INVALID = -1;
 
+    /** Logical address used to indicate the source comes from internal device. */
+    public static final int ADDR_INTERNAL = 0xFFFF;
+
     // TODO: Complete the list of CEC messages definition.
     public static final int MESSAGE_FEATURE_ABORT = 0x00;
     public static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b68ce36..396efff 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2372,12 +2372,10 @@
      */
     public static boolean setProcessDefaultNetwork(Network network) {
         if (network == null) {
-            NetworkUtils.unbindProcessToNetwork();
+            return NetworkUtils.unbindProcessToNetwork();
         } else {
-            NetworkUtils.bindProcessToNetwork(network.netId);
+            return NetworkUtils.bindProcessToNetwork(network.netId);
         }
-        // TODO fix return value
-        return true;
     }
 
     /**
@@ -2404,11 +2402,9 @@
      */
     public static boolean setProcessDefaultNetworkForHostResolution(Network network) {
         if (network == null) {
-            NetworkUtils.unbindProcessToNetworkForHostResolution();
+            return NetworkUtils.unbindProcessToNetworkForHostResolution();
         } else {
-            NetworkUtils.bindProcessToNetworkForHostResolution(network.netId);
+            return NetworkUtils.bindProcessToNetworkForHostResolution(network.netId);
         }
-        // TODO hook up the return value.
-        return true;
     }
 }
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 0a422c6..9a22d78 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -24,6 +24,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.net.SocketException;
 import java.net.UnknownHostException;
 import javax.net.SocketFactory;
 
@@ -148,7 +149,9 @@
             // Query a property of the underlying socket to ensure the underlying
             // socket exists so a file descriptor is available to bind to a network.
             socket.getReuseAddress();
-            NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId);
+            if (!NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId)) {
+                throw new SocketException("Failed to bind socket to network.");
+            }
             return socket;
         }
     }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 352512e..1a9a6378 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -20,6 +20,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.content.Intent;
+import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -38,7 +39,9 @@
  * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
  * <li>Includes a receiver for {@link #ACTION_SCORE_NETWORKS} guarded by the
  *     {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission which scores networks
- *     and (eventually) calls {@link #updateScores} with the results.
+ *     and (eventually) calls {@link #updateScores} with the results. If this receiver specifies an
+ *     android:label attribute, this label will be used when referring to the application throughout
+ *     system settings; otherwise, the application label will be used.
  * </ul>
  *
  * <p>The system keeps track of an active scorer application; at any time, only this application
@@ -105,7 +108,11 @@
      *         scorer.
      */
     public String getActiveScorerPackage() {
-        return NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData app = NetworkScorerAppManager.getActiveScorer(mContext);
+        if (app == null) {
+            return null;
+        }
+        return app.mPackageName;
     }
 
     /**
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 3660e7a..7c61710 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -24,7 +24,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -35,6 +34,8 @@
 /**
  * Internal class for managing the primary network scorer application.
  *
+ * TODO: Rename this to something more generic.
+ *
  * @hide
  */
 public final class NetworkScorerAppManager {
@@ -46,8 +47,21 @@
     /** This class cannot be instantiated. */
     private NetworkScorerAppManager() {}
 
+    public static class NetworkScorerAppData {
+        /** Package name of this scorer app. */
+        public final String mPackageName;
+
+        /** Name of this scorer app for display. */
+        public final CharSequence mScorerName;
+
+        public NetworkScorerAppData(String packageName, CharSequence scorerName) {
+            mScorerName = scorerName;
+            mPackageName = packageName;
+        }
+    }
+
     /**
-     * Returns the list of available scorer app package names.
+     * Returns the list of available scorer apps.
      *
      * <p>A network scorer is any application which:
      * <ul>
@@ -58,8 +72,8 @@
      *
      * @return the list of scorers, or the empty list if there are no valid scorers.
      */
-    public static Collection<String> getAllValidScorers(Context context) {
-        List<String> scorers = new ArrayList<>();
+    public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
+        List<NetworkScorerAppData> scorers = new ArrayList<>();
 
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> receivers = pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */);
@@ -81,33 +95,32 @@
                 // approved it as a network scorer.
                 continue;
             }
-            scorers.add(receiverInfo.packageName);
+            // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app
+            // label if none is present.
+            scorers.add(new NetworkScorerAppData(
+                    receiverInfo.packageName, receiverInfo.loadLabel(pm)));
         }
 
         return scorers;
     }
 
     /**
-     * Get the application package name to use for scoring networks.
+     * Get the application to use for scoring networks.
      *
-     * @return the scorer package or null if scoring is disabled (including if no scorer was ever
+     * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
      *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
      *     it was disabled or uninstalled).
      */
-    public static String getActiveScorer(Context context) {
+    public static NetworkScorerAppData getActiveScorer(Context context) {
         String scorerPackage = Settings.Global.getString(context.getContentResolver(),
-                Global.NETWORK_SCORER_APP);
-        if (isPackageValidScorer(context, scorerPackage)) {
-            return scorerPackage;
-        } else {
-            return null;
-        }
+                Settings.Global.NETWORK_SCORER_APP);
+        return getScorer(context, scorerPackage);
     }
 
     /**
      * Set the specified package as the default scorer application.
      *
-     * <p>The caller must have permission to write to {@link Settings.Global}.
+     * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
      *
      * @param context the context of the calling application
      * @param packageName the packageName of the new scorer to use. If null, scoring will be
@@ -125,12 +138,12 @@
         Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
 
         if (packageName == null) {
-            Settings.Global.putString(context.getContentResolver(), Global.NETWORK_SCORER_APP,
-                    null);
+            Settings.Global.putString(context.getContentResolver(),
+                    Settings.Global.NETWORK_SCORER_APP, null);
             return true;
         } else {
             // We only make the change if the new package is valid.
-            if (isPackageValidScorer(context, packageName)) {
+            if (getScorer(context, packageName) != null) {
                 Settings.Global.putString(context.getContentResolver(),
                         Settings.Global.NETWORK_SCORER_APP, packageName);
                 return true;
@@ -143,22 +156,30 @@
 
     /** Determine whether the application with the given UID is the enabled scorer. */
     public static boolean isCallerActiveScorer(Context context, int callingUid) {
-        String defaultApp = getActiveScorer(context);
+        NetworkScorerAppData defaultApp = getActiveScorer(context);
         if (defaultApp == null) {
             return false;
         }
         AppOpsManager appOpsMgr = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         try {
-            appOpsMgr.checkPackage(callingUid, defaultApp);
+            appOpsMgr.checkPackage(callingUid, defaultApp.mPackageName);
             return true;
         } catch (SecurityException e) {
             return false;
         }
     }
 
-    /** Returns true if the given package is a valid scorer. */
-    public static boolean isPackageValidScorer(Context context, String packageName) {
-        Collection<String> applications = getAllValidScorers(context);
-        return packageName != null && applications.contains(packageName);
+    /** Returns the {@link NetworkScorerAppData} for the given app, or null if it's not a scorer. */
+    public static NetworkScorerAppData getScorer(Context context, String packageName) {
+        if (TextUtils.isEmpty(packageName)) {
+            return null;
+        }
+        Collection<NetworkScorerAppData> applications = getAllValidScorers(context);
+        for (NetworkScorerAppData app : applications) {
+            if (packageName.equals(app.mPackageName)) {
+                return app;
+            }
+        }
+        return null;
     }
 }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 15c0a71..c4b17b6 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -118,13 +118,13 @@
      * is by design so an application doesn't accidentally use sockets it thinks are still bound to
      * a particular {@code Network}.
      */
-    public native static void bindProcessToNetwork(int netId);
+    public native static boolean bindProcessToNetwork(int netId);
 
     /**
      * Clear any process specific {@code Network} binding.  This reverts a call to
      * {@link #bindProcessToNetwork}.
      */
-    public native static void unbindProcessToNetwork();
+    public native static boolean unbindProcessToNetwork();
 
     /**
      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
@@ -138,7 +138,7 @@
      *
      * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
      */
-    public native static void bindProcessToNetworkForHostResolution(int netId);
+    public native static boolean bindProcessToNetworkForHostResolution(int netId);
 
     /**
      * Clears any process specific {@link Network} binding for host resolution.  This does
@@ -146,13 +146,13 @@
      *
      * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
      */
-    public native static void unbindProcessToNetworkForHostResolution();
+    public native static boolean unbindProcessToNetworkForHostResolution();
 
     /**
      * Explicitly binds {@code socketfd} to the network designated by {@code netId}.  This
      * overrides any binding via {@link #bindProcessToNetwork}.
      */
-    public native static void bindSocketToNetwork(int socketfd, int netId);
+    public native static boolean bindSocketToNetwork(int socketfd, int netId);
 
     /**
      * Convert a IPv4 address from an integer to an InetAddress.
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index d86b699..ddc185c 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -21,9 +21,6 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
@@ -180,12 +177,6 @@
     private boolean mValid;
     private final long mNativeRenderNode;
 
-    // We need to keep a strong reference to all running animators to ensure that
-    // they can call removeAnimator when they have finished, as the native-side
-    // object can only hold a WeakReference<> to avoid leaking memory due to
-    // cyclic references.
-    private List<RenderNodeAnimator> mActiveAnimators;
-
     private RenderNode(String name) {
         mNativeRenderNode = nCreate(name);
     }
@@ -866,18 +857,9 @@
     ///////////////////////////////////////////////////////////////////////////
 
     public void addAnimator(RenderNodeAnimator animator) {
-        if (mActiveAnimators == null) {
-            mActiveAnimators = new ArrayList<RenderNodeAnimator>();
-        }
-        mActiveAnimators.add(animator);
         nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
     }
 
-    public void removeAnimator(RenderNodeAnimator animator) {
-        nRemoveAnimator(mNativeRenderNode, animator.getNativeAnimator());
-        mActiveAnimators.remove(animator);
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
@@ -960,7 +942,6 @@
     ///////////////////////////////////////////////////////////////////////////
 
     private static native void nAddAnimator(long renderNode, long animatorPtr);
-    private static native void nRemoveAnimator(long renderNode, long animatorPtr);
 
     ///////////////////////////////////////////////////////////////////////////
     // Finalization
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 4979059..1363a5c 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -172,12 +172,14 @@
 
     @Override
     public void cancel() {
-        mTarget.removeAnimator(this);
+        if (!mFinished) {
+            nCancel(mNativePtr.get());
 
-        final ArrayList<AnimatorListener> listeners = getListeners();
-        final int numListeners = listeners == null ? 0 : listeners.size();
-        for (int i = 0; i < numListeners; i++) {
-            listeners.get(i).onAnimationCancel(this);
+            final ArrayList<AnimatorListener> listeners = getListeners();
+            final int numListeners = listeners == null ? 0 : listeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                listeners.get(i).onAnimationCancel(this);
+            }
         }
     }
 
@@ -219,10 +221,6 @@
         return mTarget;
     }
 
-    /**
-     * WARNING: May only be called once!!!
-     * TODO: Fix above -_-
-     */
     public void setStartValue(float startValue) {
         checkMutable();
         nSetStartValue(mNativePtr.get(), startValue);
@@ -231,6 +229,9 @@
     @Override
     public void setStartDelay(long startDelay) {
         checkMutable();
+        if (startDelay < 0) {
+            throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
+        }
         nSetStartDelay(mNativePtr.get(), startDelay);
     }
 
@@ -242,6 +243,9 @@
     @Override
     public RenderNodeAnimator setDuration(long duration) {
         checkMutable();
+        if (duration < 0) {
+            throw new IllegalArgumentException("duration must be positive; " + duration);
+        }
         nSetDuration(mNativePtr.get(), duration);
         return this;
     }
@@ -269,7 +273,6 @@
 
     private void onFinished() {
         mFinished = true;
-        mTarget.removeAnimator(this);
 
         final ArrayList<AnimatorListener> listeners = getListeners();
         final int numListeners = listeners == null ? 0 : listeners.size();
@@ -296,10 +299,13 @@
             long canvasProperty, float finalValue);
     private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
             long canvasProperty, int paintField, float finalValue);
+
     private static native void nSetStartValue(long nativePtr, float startValue);
     private static native void nSetDuration(long nativePtr, long duration);
     private static native long nGetDuration(long nativePtr);
     private static native void nSetStartDelay(long nativePtr, long startDelay);
     private static native long nGetStartDelay(long nativePtr);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
+
+    private static native void nCancel(long animPtr);
 }
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 66f5f6c..d3d5fff 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -21,6 +21,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Layout;
+import android.text.SpannedString;
+import android.text.TextUtils;
 import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
 
 import java.util.Objects;
@@ -40,7 +42,7 @@
     /**
      * The text, tracked as a composing region.
      */
-    private final String mComposingText;
+    private final CharSequence mComposingText;
 
     /**
      * Horizontal position of the insertion marker, in the local coordinates that will be
@@ -88,7 +90,7 @@
         mSelectionStart = source.readInt();
         mSelectionEnd = source.readInt();
         mComposingTextStart = source.readInt();
-        mComposingText = source.readString();
+        mComposingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
         mInsertionMarkerHorizontal = source.readFloat();
         mInsertionMarkerTop = source.readFloat();
         mInsertionMarkerBaseline = source.readFloat();
@@ -109,7 +111,7 @@
         dest.writeInt(mSelectionStart);
         dest.writeInt(mSelectionEnd);
         dest.writeInt(mComposingTextStart);
-        dest.writeString(mComposingText);
+        TextUtils.writeToParcel(mComposingText, dest, flags);
         dest.writeFloat(mInsertionMarkerHorizontal);
         dest.writeFloat(mInsertionMarkerTop);
         dest.writeFloat(mInsertionMarkerBaseline);
@@ -210,12 +212,13 @@
             if (composingText == null) {
                 mComposingText = null;
             } else {
-                mComposingText = composingText.toString();
+                // Make a snapshot of the given char sequence.
+                mComposingText = new SpannedString(composingText);
             }
             return this;
         }
         private int mComposingTextStart = -1;
-        private String mComposingText = null;
+        private CharSequence mComposingText = null;
 
         /**
          * Sets the location of the text insertion point (zero width cursor) as a rectangle in
@@ -362,7 +365,7 @@
      * Returns the entire composing text.
      * @return null if there is no composition.
      */
-    public String getComposingText() {
+    public CharSequence getComposingText() {
         return mComposingText;
     }
 
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 321d9d3..2564ff0 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -68,7 +68,36 @@
         throw new MustOverrideException();
     }
 
-     /**
+    /**
+     * Sets whether the {@link WebView} should allow third party cookies to be set.
+     * Allowing third party cookies is a per WebView policy and can be set
+     * differently on different WebView instances.
+     * <p>
+     * Apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below
+     * default to allowing third party cookies. Apps targeting
+     * {@link android.os.Build.VERSION_CODES#L} or later default to disallowing
+     * third party cookies.
+     *
+     * @param webview the {@link WebView} instance to set the cookie policy on
+     * @param accept whether the {@link WebView} instance should accept
+     *               third party cookies
+     */
+    public synchronized void setAcceptThirdPartyCookies(WebView webview,
+            boolean accept) {
+        throw new MustOverrideException();
+    }
+
+    /**
+     * Gets whether the {@link WebView} should allow third party cookies to be set.
+     *
+     * @param webview the {@link WebView} instance to get the cookie policy for
+     * @return true if the {@link WebView} accepts third party cookies
+     */
+    public synchronized boolean acceptThirdPartyCookies(WebView webview) {
+        throw new MustOverrideException();
+    }
+
+    /**
      * Sets a cookie for the given URL. Any existing cookie with the same host,
      * path and name will be replaced with the new cookie. The cookie being set
      * will be ignored if it is expired.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index d14c19b..44301c3 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -500,6 +500,24 @@
     }
 
     /**
+     * Sets policy for third party cookies.
+     * Developers should access this via {@link CookieManager#setShouldAcceptThirdPartyCookies}.
+     * @hide Internal API.
+     */
+    public void setAcceptThirdPartyCookies(boolean accept) {
+        throw new MustOverrideException();
+    }
+
+    /**
+     * Gets policy for third party cookies.
+     * Developers should access this via {@link CookieManager#getShouldAcceptThirdPartyCookies}.
+     * @hide Internal API
+     */
+    public boolean getAcceptThirdPartyCookies() {
+        throw new MustOverrideException();
+    }
+
+    /**
      * Sets the text size of the page. The default is {@link TextSize#NORMAL}.
      *
      * @param t the text size as a {@link TextSize} value
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index 7dd8dd8..ff905bb 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -21,6 +21,16 @@
 import android.net.RouteInfo;
 import android.util.Log;
 
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * Keeps track of link configuration received from Netlink.
  *
@@ -67,6 +77,7 @@
     private final String mInterfaceName;
     private final Callback mCallback;
     private final LinkProperties mLinkProperties;
+    private DnsServerRepository mDnsServerRepository;
 
     private static final boolean DBG = true;
 
@@ -76,6 +87,7 @@
         mCallback = callback;
         mLinkProperties = new LinkProperties();
         mLinkProperties.setInterfaceName(mInterfaceName);
+        mDnsServerRepository = new DnsServerRepository();
     }
 
     private void maybeLog(String operation, String iface, LinkAddress address) {
@@ -147,6 +159,20 @@
         }
     }
 
+    @Override
+    public void interfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
+            boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
+            if (changed) {
+                synchronized (this) {
+                    mDnsServerRepository.setDnsServersOn(mLinkProperties);
+                }
+                mCallback.update();
+            }
+        }
+    }
+
     /**
      * Returns a copy of this object's LinkProperties.
      */
@@ -155,7 +181,185 @@
     }
 
     public synchronized void clearLinkProperties() {
+        // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
+        // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
+        // mLinkProperties, as desired.
+        mDnsServerRepository = new DnsServerRepository();
         mLinkProperties.clear();
         mLinkProperties.setInterfaceName(mInterfaceName);
     }
 }
+
+/**
+ * Represents a DNS server entry with an expiry time.
+ *
+ * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
+ * The ordering of entries with the same lifetime is unspecified, because given two servers with
+ * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
+ * faster than comparing the IP address as well.
+ *
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ */
+class DnsServerEntry implements Comparable<DnsServerEntry> {
+    /** The IP address of the DNS server. */
+    public final InetAddress address;
+    /** The time until which the DNS server may be used. A Java millisecond time as might be
+      * returned by currentTimeMillis(). */
+    public long expiry;
+
+    public DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
+        this.address = address;
+        this.expiry = expiry;
+    }
+
+    public int compareTo(DnsServerEntry other) {
+        return Long.compare(other.expiry, this.expiry);
+    }
+}
+
+/**
+ * Tracks DNS server updates received from Netlink.
+ *
+ * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
+ * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be used
+ * any more. In this way, the network can gracefully migrate clients from one set of DNS servers to
+ * another. Announcements can both raise and lower the lifetime, and an announcement can expire
+ * servers by announcing them with a lifetime of zero.
+ *
+ * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of DNS
+ * servers at any given time. These are referred to as the current servers. In case all the
+ * current servers expire, the class also keeps track of a larger (but limited) number of servers
+ * that are promoted to current servers when the current ones expire. In order to minimize updates
+ * to the rest of the system (and potentially expensive cache flushes) this class attempts to keep
+ * the list of current servers constant where possible. More specifically, the list of current
+ * servers is only updated if a new server is learned and there are not yet {@code
+ * NUM_CURRENT_SERVERS} current servers, or if one or more of the current servers expires or is
+ * pushed out of the set. Therefore, the current servers will not necessarily be the ones with the
+ * highest lifetime, but the ones learned first.
+ *
+ * This is by design: if instead the class always preferred the servers with the highest lifetime, a
+ * (misconfigured?) network where two or more routers announce more than {@code NUM_CURRENT_SERVERS}
+ * unique servers would cause persistent oscillations.
+ *
+ * TODO: Currently servers are only expired when a new DNS update is received.
+ * Update them using timers, or possibly on every notification received by NetlinkTracker.
+ *
+ * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
+ * notifications are sent by multiple threads. If future threads use alarms to expire, those
+ * alarms must also be synchronized(this).
+ *
+ */
+class DnsServerRepository {
+
+    /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
+    public static final int NUM_CURRENT_SERVERS = 3;
+
+    /** How many DNS servers we'll keep track of, in total. */
+    public static final int NUM_SERVERS = 12;
+
+    /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
+    private Set<InetAddress> mCurrentServers;
+
+    public static final String TAG = "DnsServerRepository";
+
+    /**
+     * Stores all the DNS servers we know about, for use when the current servers expire.
+     * Always sorted in order of decreasing expiry. The elements in this list are also the values
+     * of mIndex, and may be elements in mCurrentServers.
+     */
+    private ArrayList<DnsServerEntry> mAllServers;
+
+    /**
+     * Indexes the servers so we can update their lifetimes more quickly in the common case where
+     * servers are not being added, but only being refreshed.
+     */
+    private HashMap<InetAddress, DnsServerEntry> mIndex;
+
+    public DnsServerRepository() {
+        mCurrentServers = new HashSet();
+        mAllServers = new ArrayList<DnsServerEntry>(NUM_SERVERS);
+        mIndex = new HashMap<InetAddress, DnsServerEntry>(NUM_SERVERS);
+    }
+
+    /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
+    public synchronized void setDnsServersOn(LinkProperties lp) {
+        lp.setDnsServers(mCurrentServers);
+    }
+
+    /**
+     * Notifies the class of new DNS server information.
+     * @param lifetime the time in seconds that the DNS servers are valid.
+     * @param addresses the string representations of the IP addresses of the DNS servers to use.
+     */
+    public synchronized boolean addServers(long lifetime, String[] addresses) {
+        // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
+        // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
+        // (136 years) is close enough.
+        long now = System.currentTimeMillis();
+        long expiry = now + 1000 * lifetime;
+
+        // Go through the list of servers. For each one, update the entry if one exists, and
+        // create one if it doesn't.
+        for (String addressString : addresses) {
+            InetAddress address;
+            try {
+                address = InetAddress.parseNumericAddress(addressString);
+            } catch (IllegalArgumentException ex) {
+                continue;
+            }
+
+            if (!updateExistingEntry(address, expiry)) {
+                // There was no entry for this server. Create one, unless it's already expired
+                // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
+                if (expiry > now) {
+                    DnsServerEntry entry = new DnsServerEntry(address, expiry);
+                    mAllServers.add(entry);
+                    mIndex.put(address, entry);
+                }
+            }
+        }
+
+        // Sort the servers by expiry.
+        Collections.sort(mAllServers);
+
+        // Prune excess entries and update the current server list.
+        return updateCurrentServers();
+    }
+
+    private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
+        DnsServerEntry existing = mIndex.get(address);
+        if (existing != null) {
+            existing.expiry = expiry;
+            return true;
+        }
+        return false;
+    }
+
+    private synchronized boolean updateCurrentServers() {
+        long now = System.currentTimeMillis();
+        boolean changed = false;
+
+        // Prune excess or expired entries.
+        for (int i = mAllServers.size() - 1; i >= 0; i--) {
+            if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
+                DnsServerEntry removed = mAllServers.remove(i);
+                mIndex.remove(removed.address);
+                changed |= mCurrentServers.remove(removed.address);
+            } else {
+                break;
+            }
+        }
+
+        // Add servers to the current set, in order of decreasing lifetime, until it has enough.
+        // Prefer existing servers over new servers in order to minimize updates to the rest of the
+        // system and avoid persistent oscillations.
+        for (DnsServerEntry entry : mAllServers) {
+            if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
+                changed |= mCurrentServers.add(entry.address);
+            } else {
+                break;
+            }
+        }
+        return changed;
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index cb00062..f287fca 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -105,6 +105,8 @@
 	android/graphics/Interpolator.cpp \
 	android/graphics/MaskFilter.cpp \
 	android/graphics/Matrix.cpp \
+	android/graphics/MinikinSkia.cpp \
+	android/graphics/MinikinUtils.cpp \
 	android/graphics/Movie.cpp \
 	android/graphics/NinePatch.cpp \
 	android/graphics/NinePatchImpl.cpp \
@@ -120,8 +122,6 @@
 	android/graphics/Region.cpp \
 	android/graphics/Shader.cpp \
 	android/graphics/SurfaceTexture.cpp \
-	android/graphics/TextLayout.cpp \
-	android/graphics/TextLayoutCache.cpp \
 	android/graphics/Typeface.cpp \
 	android/graphics/TypefaceImpl.cpp \
 	android/graphics/Utils.cpp \
@@ -197,6 +197,9 @@
 	frameworks/opt/emoji \
 	libcore/include \
 	$(call include-path-for, audio-utils) \
+	frameworks/minikin/include \
+	external/freetype/include
+# TODO: clean up Minikin so it doesn't need the freetype include
 
 LOCAL_SHARED_LIBRARIES := \
 	libmemtrack \
@@ -237,23 +240,14 @@
 	libpdfium \
 	libimg_utils \
 	libnetd_client \
-	libsoundtrigger
+	libsoundtrigger \
+	libminikin \
+	libstlport
 
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
 endif
 
-ifeq ($(USE_MINIKIN), true)
-	LOCAL_CFLAGS += -DUSE_MINIKIN
-	LOCAL_C_INCLUDES += frameworks/minikin/include \
-		external/freetype/include
-	LOCAL_SRC_FILES += 	android/graphics/MinikinSkia.cpp \
-		android/graphics/MinikinUtils.cpp
-# note: the freetype include is spurious; minikin itself probably
-# shouldn't depend on it
-	LOCAL_SHARED_LIBRARIES += libminikin libstlport
-endif
-
 LOCAL_SHARED_LIBRARIES += \
 	libdl
 # we need to access the private Bionic header
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 9e09280..3f323ab 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -29,14 +29,10 @@
 #include "SkTArray.h"
 #include "SkTemplates.h"
 
-#ifdef USE_MINIKIN
 #include <minikin/Layout.h>
 #include "MinikinSkia.h"
 #include "MinikinUtils.h"
-#endif
 
-#include "TextLayout.h"
-#include "TextLayoutCache.h"
 #include "TypefaceImpl.h"
 
 #include "unicode/ubidi.h"
@@ -301,7 +297,7 @@
     }
 
     static void freeTextLayoutCaches(JNIEnv* env, jobject) {
-        TextLayoutEngine::getInstance().purgeCaches();
+        Layout::purgeCaches();
     }
 
     static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
@@ -904,7 +900,6 @@
         env->ReleaseStringChars(text, textArray);
     }
 
-#ifdef USE_MINIKIN
     class DrawTextFunctor {
     public:
         DrawTextFunctor(const Layout& layout, SkCanvas* canvas, jfloat x, jfloat y, SkPaint* paint,
@@ -946,7 +941,6 @@
         delete[] glyphs;
         delete[] pos;
     }
-#endif
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
@@ -961,29 +955,10 @@
             int start, int count, int contextCount,
             jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(textArray, start, count, contextCount, css);
         drawGlyphsToSkia(canvas, paint, layout, x, y);
-#else
-        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                textArray, start, count, contextCount, bidiFlags);
-        if (value == NULL) {
-            return;
-        }
-        SkPaint::Align align = paint->getTextAlign();
-        if (align == SkPaint::kCenter_Align) {
-            x -= 0.5 * value->getTotalAdvance();
-        } else if (align == SkPaint::kRight_Align) {
-            x -= value->getTotalAdvance();
-        }
-        paint->setTextAlign(SkPaint::kLeft_Align);
-        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(),
-                x, y, paint);
-        doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
-        paint->setTextAlign(align);
-#endif
     }
 
 // Same values used by Skia
@@ -1124,7 +1099,6 @@
         delete[] posPtr;
     }
 
-#ifdef USE_MINIKIN
     class DrawTextOnPathFunctor {
     public:
         DrawTextOnPathFunctor(const Layout& layout, SkCanvas* canvas, float hOffset,
@@ -1149,11 +1123,9 @@
         SkPaint* paint;
         SkPath* path;
     };
-#endif
 
     static void doDrawTextOnPath(SkPaint* paint, const jchar* text, int count, int bidiFlags,
             float hOffset, float vOffset, SkPath* path, SkCanvas* canvas, TypefaceImpl* typeface) {
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(text, 0, count, count, css);
@@ -1167,9 +1139,6 @@
         DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paint, path);
         MinikinUtils::forFontRun(layout, paint, f);
         paint->setTextAlign(align);
-#else
-        TextLayout::drawTextOnPath(paint, text, count, bidiFlags, hOffset, vOffset, path, canvas);
-#endif
     }
 
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index dd6b36f..1d465b3 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -27,44 +27,34 @@
 #include <androidfw/AssetManager.h>
 #include "Utils.h"
 
-#ifdef USE_MINIKIN
+#include "TypefaceImpl.h"
 #include <minikin/FontFamily.h>
 #include "MinikinSkia.h"
-#endif
 
 namespace android {
 
 static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
-#ifdef USE_MINIKIN
     FontLanguage fontLanguage;
     if (lang != NULL) {
         ScopedUtfChars str(env, lang);
         fontLanguage = FontLanguage(str.c_str(), str.size());
     }
     return (jlong)new FontFamily(fontLanguage, variant);
-#else
-    return 0;
-#endif
 }
 
 static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
-#ifdef USE_MINIKIN
     FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
     fontFamily->Unref();
-#endif
 }
 
-#ifdef USE_MINIKIN
 static jboolean addSkTypeface(FontFamily* family, SkTypeface* face) {
     MinikinFont* minikinFont = new MinikinFontSkia(face);
     bool result = family->addFont(minikinFont);
     minikinFont->Unref();
     return result;
 }
-#endif
 
 static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path) {
-#ifdef USE_MINIKIN
     NPE_CHECK_RETURN_ZERO(env, path);
     ScopedUtfChars str(env, path);
     SkTypeface* face = SkTypeface::CreateFromFile(str.c_str());
@@ -74,14 +64,10 @@
     }
     FontFamily* fontFamily = (FontFamily*)familyPtr;
     return addSkTypeface(fontFamily, face);
-#else
-    return false;
-#endif
 }
 
 static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr,
         jobject jassetMgr, jstring jpath) {
-#ifdef USE_MINIKIN
     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
@@ -108,9 +94,6 @@
     }
     FontFamily* fontFamily = (FontFamily*)familyPtr;
     return addSkTypeface(fontFamily, face);
-#else
-    return false;
-#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index ad174f7..7fda3d9 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -8,13 +8,16 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkImageDecoder.h"
-#include "TypefaceImpl.h"
 #include <jni.h>
 
 class SkBitmapRegionDecoder;
 class SkCanvas;
 class SkPaint;
 
+namespace android {
+class TypefaceImpl;
+}
+
 class GraphicsJNI {
 public:
     enum BitmapCreateFlags {
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index fc92d53..f02f118 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -59,7 +59,6 @@
     SkPaintOptionsAndroid::FontVariant var = paint->getPaintOptionsAndroid().getFontVariant();
     const char* varstr = var == SkPaintOptionsAndroid::kElegant_Variant ? "elegant" : "compact";
     off = snprintfcat(css, off, sizeof(css), " -minikin-variant: %s;", varstr);
-    layout->setProperties(css);
     return std::string(css);
 }
 
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index b2662a1..1663860 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -26,6 +26,18 @@
 
 namespace android {
 
+// TODO: these should be defined in Minikin's Layout.h
+enum {
+    kBidi_LTR = 0,
+    kBidi_RTL = 1,
+    kBidi_Default_LTR = 2,
+    kBidi_Default_RTL = 3,
+    kBidi_Force_LTR = 4,
+    kBidi_Force_RTL = 5,
+
+    kBidi_Mask = 0x7
+};
+
 class Layout;
 class TypefaceImpl;
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index dc30814..0ad390a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -34,14 +34,12 @@
 #include "unicode/uloc.h"
 #include "unicode/ushape.h"
 #include "utils/Blur.h"
-#include "TextLayout.h"
 
-#ifdef USE_MINIKIN
 #include <minikin/GraphemeBreak.h>
 #include <minikin/Layout.h>
 #include "MinikinSkia.h"
 #include "MinikinUtils.h"
-#endif
+#include "TypefaceImpl.h"
 
 // temporary for debugging
 #include <Caches.h>
@@ -304,14 +302,8 @@
     }
 
     static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
-#ifndef USE_MINIKIN
-        SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle);
-        SkTypeface* typeface = reinterpret_cast<SkTypeface*>(typefaceHandle);
-        return reinterpret_cast<jlong>(obj->setTypeface(typeface));
-#else
-        // TODO(raph): not yet implemented
+        // TODO: in Paint refactoring, set typeface on android Paint, not SkPaint
         return NULL;
-#endif
     }
 
     static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
@@ -437,22 +429,18 @@
         const int kElegantDescent = -500;
         const int kElegantLeading = 0;
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
-#ifdef USE_MINIKIN
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
         typeface = TypefaceImpl_resolveDefault(typeface);
         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
         float saveSkewX = paint->getTextSkewX();
         bool savefakeBold = paint->isFakeBoldText();
         MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
-#endif
         SkScalar spacing = paint->getFontMetrics(metrics);
-#ifdef USE_MINIKIN
         // The populateSkPaint call may have changed fake bold / text skew
         // because we want to measure with those effects applied, so now
         // restore the original settings.
         paint->setTextSkewX(saveSkewX);
         paint->setFakeBoldText(savefakeBold);
-#endif
         SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid();
         if (paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant) {
             SkScalar size = paint->getTextSize();
@@ -534,17 +522,11 @@
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = 0;
 
-#ifdef USE_MINIKIN
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(textArray, index, count, textLength, css);
         result = layout.getAdvance();
-#else
-        TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
-                bidiFlags, NULL /* dont need all advances */, &result);
-#endif
-
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
     }
@@ -568,16 +550,11 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         jfloat width = 0;
 
-#ifdef USE_MINIKIN
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(textArray, start, count, textLength, css);
         width = layout.getAdvance();
-#else
-        TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
-                bidiFlags, NULL /* dont need all advances */, &width);
-#endif
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -596,16 +573,11 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         jfloat width = 0;
 
-#ifdef USE_MINIKIN
         Layout layout;
         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(textArray, 0, textLength, textLength, css);
         width = layout.getAdvance();
-#else
-        TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
-                bidiFlags, NULL /* dont need all advances */, &width);
-#endif
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -632,15 +604,10 @@
         AutoJavaFloatArray autoWidths(env, widths, count);
         jfloat* widthsArray = autoWidths.ptr();
 
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(text, 0, count, count, css);
         layout.getAdvances(widthsArray);
-#else
-        TextLayout::getTextRunAdvances(paint, text, 0, count, count,
-                bidiFlags, widthsArray, NULL /* dont need totalAdvance */);
-#endif
 
         return count;
     }
@@ -666,47 +633,6 @@
         return count;
     }
 
-    static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
-            jint contextCount, jint flags, jcharArray glyphs) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-        size_t glypthsLength = env->GetArrayLength(glyphs);
-        if ((size_t)count > glypthsLength) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-
-        jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
-
-        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                text, start, count, contextCount, flags);
-        const jchar* shapedGlyphs = value->getGlyphs();
-        size_t glyphsCount = value->getGlyphsCount();
-        memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
-
-        env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
-        return glyphsCount;
-    }
-
-    static jint getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, jlong paintHandle,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
-            jcharArray glyphs) {
-        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
-                end - start, contextEnd - contextStart, flags, glyphs);
-        env->ReleaseStringChars(text, textArray);
-        return count;
-    }
-
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text,
                                     jint start, jint count, jint contextCount, jboolean isRtl,
                                     jfloatArray advances, jint advancesIndex) {
@@ -732,16 +658,11 @@
 
         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
 
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(text, start, count, contextCount, css);
         layout.getAdvances(advancesArray);
         totalAdvance = layout.getAdvance();
-#else
-        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, bidiFlags,
-                                       advancesArray, &totalAdvance);
-#endif
 
         if (advances != NULL) {
             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
@@ -779,52 +700,9 @@
 
     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
             jint count, jint flags, jint offset, jint opt) {
-#ifdef USE_MINIKIN
         GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt);
         size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt);
         return static_cast<jint>(result);
-#else
-        jfloat scalarArray[count];
-
-        TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
-                scalarArray, NULL /* dont need totalAdvance */);
-
-        jint pos = offset - start;
-        switch (opt) {
-        case AFTER:
-          if (pos < count) {
-            pos += 1;
-          }
-          // fall through
-        case AT_OR_AFTER:
-          while (pos < count && scalarArray[pos] == 0) {
-            ++pos;
-          }
-          break;
-        case BEFORE:
-          if (pos > 0) {
-            --pos;
-          }
-          // fall through
-        case AT_OR_BEFORE:
-          while (pos > 0 && scalarArray[pos] == 0) {
-            --pos;
-          }
-          break;
-        case AT:
-        default:
-          if (scalarArray[pos] == 0) {
-            pos = -1;
-          }
-          break;
-        }
-
-        if (pos != -1) {
-          pos += start;
-        }
-
-        return pos;
-#endif
     }
 
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
@@ -847,7 +725,6 @@
         return result;
     }
 
-#ifdef USE_MINIKIN
     class GetTextFunctor {
     public:
         GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, SkPaint* paint,
@@ -878,11 +755,9 @@
         SkPoint* pos;
         SkPath tmpPath;
     };
-#endif
 
     static void getTextPath(JNIEnv* env, SkPaint* paint, TypefaceImpl* typeface, const jchar* text,
             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(text, 0, count, count, css);
@@ -899,9 +774,6 @@
         paint->setTextAlign(align);
         delete[] glyphs;
         delete[] pos;
-#else
-        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
-#endif
     }
 
     static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
@@ -949,7 +821,6 @@
         size_t measuredCount = 0;
         float measured = 0;
 
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
         layout.doLayout(text, 0, count, count, css);
@@ -970,19 +841,6 @@
             measured += width;
         }
         delete[] advances;
-#else
-        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, bidiFlags);
-        if (value == NULL) {
-            return 0;
-        }
-        SkScalar m;
-        size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
-                maxWidth, &m, textBufferDirection);
-        SkASSERT((bytes & 1) == 0);
-        measuredCount = bytes >> 1;
-        measured = SkScalarToFloat(m);
-#endif
 
         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
@@ -1044,7 +902,6 @@
         SkRect  r;
         SkIRect ir;
 
-#ifdef USE_MINIKIN
         Layout layout;
         std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
         layout.doLayout(text, 0, count, count, css);
@@ -1054,14 +911,6 @@
         r.fTop = rect.mTop;
         r.fRight = rect.mRight;
         r.fBottom = rect.mBottom;
-#else
-        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, bidiFlags);
-        if (value == NULL) {
-            return;
-        }
-        paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r);
-#endif
         r.roundOut(&ir);
         GraphicsJNI::irect_to_jrect(ir, env, bounds);
     }
@@ -1154,9 +1003,6 @@
     {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
         (void*) SkPaintGlue::getTextRunAdvances__StringIIIIZ_FI},
 
-
-    {"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I",
-        (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
     {"native_getTextRunCursor", "(J[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
     {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 621534e..eea16f1 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -227,7 +227,7 @@
     }
 }
 
-static void SurfaceTexture_init(JNIEnv* env, jobject thiz,
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
         jint texName, jboolean singleBufferMode, jobject weakThiz)
 {
     sp<IGraphicBufferProducer> producer;
@@ -239,8 +239,15 @@
         consumer->setDefaultMaxBufferCount(1);
     }
 
-    sp<GLConsumer> surfaceTexture(new GLConsumer(consumer, texName,
-            GL_TEXTURE_EXTERNAL_OES, true, true));
+    sp<GLConsumer> surfaceTexture;
+    if (isDetached) {
+        surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,
+                true, true);
+    } else {
+        surfaceTexture = new GLConsumer(consumer, texName,
+                GL_TEXTURE_EXTERNAL_OES, true, true);
+    }
+
     if (surfaceTexture == 0) {
         jniThrowException(env, OutOfResourcesException,
                 "Unable to create native SurfaceTexture");
@@ -338,7 +345,7 @@
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
-    {"nativeInit",                 "(IZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
+    {"nativeInit",                 "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
     {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
deleted file mode 100644
index d0b6f7c..0000000
--- a/core/jni/android/graphics/TextLayout.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "TextLayout"
-
-#include "TextLayout.h"
-#include "TextLayoutCache.h"
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include "SkTemplates.h"
-#include "unicode/ubidi.h"
-#include "unicode/ushape.h"
-#include <utils/Log.h>
-
-namespace android {
-
-// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
-// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
-// looking for a character >= the first RTL character in unicode and assume we do if
-// we find one.
-bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
-    if (bidiFlags == kBidi_Force_LTR) {
-        return false;
-    }
-    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
-            bidiFlags == kBidi_Force_RTL) {
-        return true;
-    }
-    for (int i = 0; i < len; ++i) {
-        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
-            return true;
-        }
-    }
-    return false;
-}
-
-// Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
-// This will draw if canvas is not null, otherwise path must be non-null and it will create
-// a path representing the text that would have been drawn.
-void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
-                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, len, len, bidiFlags);
-    if (value == NULL) {
-        return ;
-    }
-    // Beware: this needs Glyph encoding (already done on the Paint constructor)
-    paint->getTextPath(value->getGlyphs(), value->getGlyphsCount() * 2, x, y, path);
-}
-
-void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                    jint count, jint contextCount, jint dirFlags,
-                                    jfloat* resultAdvances, jfloat* resultTotalAdvance) {
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            chars, start, count, contextCount, dirFlags);
-    if (value == NULL) {
-        return ;
-    }
-    if (resultAdvances) {
-        memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
-    }
-    if (resultTotalAdvance) {
-        *resultTotalAdvance = value->getTotalAdvance();
-    }
-}
-
-void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
-                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
-    handleText(paint, text, len, bidiFlags, x, y, path);
-}
-
-
-void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
-                                int bidiFlags, jfloat hOffset, jfloat vOffset,
-                                SkPath* path, SkCanvas* canvas) {
-
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, bidiFlags);
-    if (value == NULL) {
-        return;
-    }
-
-    // Beware: this needs Glyph encoding (already done on the Paint constructor)
-    canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path,
-            hOffset, vOffset, *paint);
-}
-
-}
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
deleted file mode 100644
index 495d08a..0000000
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ /dev/null
@@ -1,948 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define LOG_TAG "TextLayoutCache"
-
-#include <utils/JenkinsHash.h>
-#include <utils/CallStack.h>
-
-#include "TextLayoutCache.h"
-#include "TextLayout.h"
-#include "SkGlyphCache.h"
-#include "SkTypeface_android.h"
-#include "HarfBuzzNGFaceSkia.h"
-#include <unicode/unistr.h>
-#include <unicode/uchar.h>
-#include <hb-icu.h>
-
-namespace android {
-
-//--------------------------------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
-
-//--------------------------------------------------------------------------------------------------
-
-TextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) :
-        mShaper(shaper),
-        mCache(LruCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
-        mCacheHitCount(0), mNanosecondsSaved(0) {
-    init();
-}
-
-TextLayoutCache::~TextLayoutCache() {
-    mCache.clear();
-}
-
-void TextLayoutCache::init() {
-    mCache.setOnEntryRemovedListener(this);
-
-    mDebugLevel = readRtlDebugLevel();
-    mDebugEnabled = mDebugLevel & kRtlDebugCaches;
-    ALOGD("Using debug level = %d - Debug Enabled = %d", mDebugLevel, mDebugEnabled);
-
-    mCacheStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
-    if (mDebugEnabled) {
-        ALOGD("Initialization is done - Start time = %lld", mCacheStartTime);
-    }
-
-    mInitialized = true;
-}
-
-/**
- *  Callbacks
- */
-void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) {
-    size_t totalSizeToDelete = text.getSize() + desc->getSize();
-    mSize -= totalSizeToDelete;
-    if (mDebugEnabled) {
-        ALOGD("Cache value %p deleted, size = %zu", desc.get(), totalSizeToDelete);
-    }
-}
-
-/*
- * Cache clearing
- */
-void TextLayoutCache::purgeCaches() {
-    AutoMutex _l(mLock);
-    mCache.clear();
-    mShaper->purgeCaches();
-}
-
-/*
- * Caching
- */
-sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
-            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
-    AutoMutex _l(mLock);
-#ifdef USE_MINIKIN
-    // We want to get rid of all legacy calls in the Minikin case, so log
-    ALOGW("TextLayoutCache being invoked!");
-    CallStack _cs(LOG_TAG);
-#endif
-    nsecs_t startTime = 0;
-    if (mDebugEnabled) {
-        startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    }
-
-    // Create the key
-    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
-
-    // Get value from cache if possible
-    sp<TextLayoutValue> value = mCache.get(key);
-
-    // Value not found for the key, we need to add a new value in the cache
-    if (value == NULL) {
-        if (mDebugEnabled) {
-            startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        }
-
-        value = new TextLayoutValue(contextCount);
-
-        // Compute advances and store them
-        mShaper->computeValues(value.get(), paint,
-                reinterpret_cast<const UChar*>(key.getText()), start, count,
-                size_t(contextCount), int(dirFlags));
-
-        if (mDebugEnabled) {
-            value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
-        }
-
-        // Don't bother to add in the cache if the entry is too big
-        size_t size = key.getSize() + value->getSize();
-        if (size <= mMaxSize) {
-            // Cleanup to make some room if needed
-            if (mSize + size > mMaxSize) {
-                if (mDebugEnabled) {
-                    ALOGD("Need to clean some entries for making some room for a new entry");
-                }
-                while (mSize + size > mMaxSize) {
-                    // This will call the callback
-                    bool removedOne = mCache.removeOldest();
-                    LOG_ALWAYS_FATAL_IF(!removedOne, "The cache is non-empty but we "
-                            "failed to remove the oldest entry.  "
-                            "mSize = %u, size = %zu, mMaxSize = %u, mCache.size() = %zu",
-                            mSize, size, mMaxSize, mCache.size());
-                }
-            }
-
-            // Update current cache size
-            mSize += size;
-
-            bool putOne = mCache.put(key, value);
-            LOG_ALWAYS_FATAL_IF(!putOne, "Failed to put an entry into the cache.  "
-                    "This indicates that the cache already has an entry with the "
-                    "same key but it should not since we checked earlier!"
-                    " - start = %d, count = %d, contextCount = %d - Text = '%s'",
-                    start, count, contextCount, String8(key.getText() + start, count).string());
-
-            if (mDebugEnabled) {
-                nsecs_t totalTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-                ALOGD("CACHE MISS: Added entry %p "
-                        "with start = %d, count = %d, contextCount = %d, "
-                        "entry size %zu bytes, remaining space %d bytes"
-                        " - Compute time %0.6f ms - Put time %0.6f ms - Text = '%s'",
-                        value.get(), start, count, contextCount, size, mMaxSize - mSize,
-                        value->getElapsedTime() * 0.000001f,
-                        (totalTime - value->getElapsedTime()) * 0.000001f,
-                        String8(key.getText() + start, count).string());
-            }
-        } else {
-            if (mDebugEnabled) {
-                ALOGD("CACHE MISS: Calculated but not storing entry because it is too big "
-                        "with start = %d, count = %d, contextCount = %d, "
-                        "entry size %zu bytes, remaining space %d bytes"
-                        " - Compute time %0.6f ms - Text = '%s'",
-                        start, count, contextCount, size, mMaxSize - mSize,
-                        value->getElapsedTime() * 0.000001f,
-                        String8(key.getText() + start, count).string());
-            }
-        }
-    } else {
-        // This is a cache hit, just log timestamp and user infos
-        if (mDebugEnabled) {
-            nsecs_t elapsedTimeThruCacheGet = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-            mNanosecondsSaved += (value->getElapsedTime() - elapsedTimeThruCacheGet);
-            ++mCacheHitCount;
-
-            if (value->getElapsedTime() > 0) {
-                float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet)
-                        / ((float)value->getElapsedTime()));
-                ALOGD("CACHE HIT #%d with start = %d, count = %d, contextCount = %d"
-                        "- Compute time %0.6f ms - "
-                        "Cache get time %0.6f ms - Gain in percent: %2.2f - Text = '%s'",
-                        mCacheHitCount, start, count, contextCount,
-                        value->getElapsedTime() * 0.000001f,
-                        elapsedTimeThruCacheGet * 0.000001f,
-                        deltaPercent,
-                        String8(key.getText() + start, count).string());
-            }
-            if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) {
-                dumpCacheStats();
-            }
-        }
-    }
-    return value;
-}
-
-void TextLayoutCache::dumpCacheStats() {
-    float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));
-    float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / 1000000000;
-
-    size_t cacheSize = mCache.size();
-
-    ALOGD("------------------------------------------------");
-    ALOGD("Cache stats");
-    ALOGD("------------------------------------------------");
-    ALOGD("pid       : %d", getpid());
-    ALOGD("running   : %.0f seconds", timeRunningInSec);
-    ALOGD("entries   : %zu", cacheSize);
-    ALOGD("max size  : %d bytes", mMaxSize);
-    ALOGD("used      : %d bytes according to mSize", mSize);
-    ALOGD("remaining : %d bytes or %2.2f percent", mMaxSize - mSize, remainingPercent);
-    ALOGD("hits      : %d", mCacheHitCount);
-    ALOGD("saved     : %0.6f ms", mNanosecondsSaved * 0.000001f);
-    ALOGD("------------------------------------------------");
-}
-
-/**
- * TextLayoutCacheKey
- */
-TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
-        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
-        hinting(SkPaint::kNo_Hinting) {
-    paintOpts.setUseFontFallbacks(true);
-}
-
-TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
-        size_t start, size_t count, size_t contextCount, int dirFlags) :
-            start(start), count(count), contextCount(contextCount),
-            dirFlags(dirFlags) {
-    textCopy.setTo(text, contextCount);
-    typeface = paint->getTypeface();
-    textSize = paint->getTextSize();
-    textSkewX = paint->getTextSkewX();
-    textScaleX = paint->getTextScaleX();
-    flags = paint->getFlags();
-    hinting = paint->getHinting();
-    paintOpts = paint->getPaintOptionsAndroid();
-}
-
-TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
-        textCopy(other.textCopy),
-        start(other.start),
-        count(other.count),
-        contextCount(other.contextCount),
-        dirFlags(other.dirFlags),
-        typeface(other.typeface),
-        textSize(other.textSize),
-        textSkewX(other.textSkewX),
-        textScaleX(other.textScaleX),
-        flags(other.flags),
-        hinting(other.hinting),
-        paintOpts(other.paintOpts) {
-}
-
-int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
-    int deltaInt = lhs.start - rhs.start;
-    if (deltaInt != 0) return (deltaInt);
-
-    deltaInt = lhs.count - rhs.count;
-    if (deltaInt != 0) return (deltaInt);
-
-    deltaInt = lhs.contextCount - rhs.contextCount;
-    if (deltaInt != 0) return (deltaInt);
-
-    if (lhs.typeface < rhs.typeface) return -1;
-    if (lhs.typeface > rhs.typeface) return +1;
-
-    if (lhs.textSize < rhs.textSize) return -1;
-    if (lhs.textSize > rhs.textSize) return +1;
-
-    if (lhs.textSkewX < rhs.textSkewX) return -1;
-    if (lhs.textSkewX > rhs.textSkewX) return +1;
-
-    if (lhs.textScaleX < rhs.textScaleX) return -1;
-    if (lhs.textScaleX > rhs.textScaleX) return +1;
-
-    deltaInt = lhs.flags - rhs.flags;
-    if (deltaInt != 0) return (deltaInt);
-
-    deltaInt = lhs.hinting - rhs.hinting;
-    if (deltaInt != 0) return (deltaInt);
-
-    deltaInt = lhs.dirFlags - rhs.dirFlags;
-    if (deltaInt) return (deltaInt);
-
-    if (lhs.paintOpts != rhs.paintOpts)
-        return memcmp(&lhs.paintOpts, &rhs.paintOpts, sizeof(SkPaintOptionsAndroid));
-
-    return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
-}
-
-size_t TextLayoutCacheKey::getSize() const {
-    return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount;
-}
-
-hash_t TextLayoutCacheKey::hash() const {
-    uint32_t hash = JenkinsHashMix(0, start);
-    hash = JenkinsHashMix(hash, count);
-    /* contextCount not needed because it's included in text, below */
-    hash = JenkinsHashMix(hash, hash_type(typeface));
-    hash = JenkinsHashMix(hash, hash_type(textSize));
-    hash = JenkinsHashMix(hash, hash_type(textSkewX));
-    hash = JenkinsHashMix(hash, hash_type(textScaleX));
-    hash = JenkinsHashMix(hash, flags);
-    hash = JenkinsHashMix(hash, hinting);
-    hash = JenkinsHashMix(hash, paintOpts.getFontVariant());
-    // Note: leaving out language is not problematic, as equality comparisons
-    // are still valid - the only bad thing that could happen is collisions.
-    hash = JenkinsHashMixShorts(hash, getText(), contextCount);
-    return JenkinsHashWhiten(hash);
-}
-
-/**
- * TextLayoutCacheValue
- */
-TextLayoutValue::TextLayoutValue(size_t contextCount) :
-        mTotalAdvance(0), mElapsedTime(0) {
-    mBounds.setEmpty();
-    // Give a hint for advances and glyphs vectors size
-    mAdvances.setCapacity(contextCount);
-    mGlyphs.setCapacity(contextCount);
-    mPos.setCapacity(contextCount * 2);
-}
-
-size_t TextLayoutValue::getSize() const {
-    return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
-            sizeof(jchar) * mGlyphs.capacity() + sizeof(jfloat) * mPos.capacity();
-}
-
-void TextLayoutValue::setElapsedTime(uint32_t time) {
-    mElapsedTime = time;
-}
-
-uint32_t TextLayoutValue::getElapsedTime() {
-    return mElapsedTime;
-}
-
-TextLayoutShaper::TextLayoutShaper() {
-    mBuffer = hb_buffer_create();
-}
-
-TextLayoutShaper::~TextLayoutShaper() {
-    hb_buffer_destroy(mBuffer);
-}
-
-void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint,
-        const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) {
-    computeValues(paint, chars, start, count, contextCount, dirFlags,
-            &value->mAdvances, &value->mTotalAdvance, &value->mBounds,
-            &value->mGlyphs, &value->mPos);
-#if DEBUG_ADVANCES
-    ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
-            contextCount, value->mTotalAdvance);
-#endif
-}
-
-void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount, int dirFlags,
-        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
-        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
-        *outTotalAdvance = 0;
-        if (!count) {
-            return;
-        }
-
-        UBiDiLevel bidiReq = 0;
-        bool forceLTR = false;
-        bool forceRTL = false;
-
-        switch (dirFlags & kBidi_Mask) {
-            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
-            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
-            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
-            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
-            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
-            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
-        }
-
-        bool useSingleRun = false;
-        bool isRTL = forceRTL;
-        if (forceLTR || forceRTL) {
-            useSingleRun = true;
-        } else {
-            UBiDi* bidi = ubidi_open();
-            if (bidi) {
-                UErrorCode status = U_ZERO_ERROR;
-#if DEBUG_GLYPHS
-                ALOGD("******** ComputeValues -- start");
-                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
-                ALOGD("      -- start = %d", start);
-                ALOGD("      -- count = %d", count);
-                ALOGD("      -- contextCount = %d", contextCount);
-                ALOGD("      -- bidiReq = %d", bidiReq);
-#endif
-                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
-                if (U_SUCCESS(status)) {
-                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
-                    ssize_t rc = ubidi_countRuns(bidi, &status);
-#if DEBUG_GLYPHS
-                    ALOGD("      -- dirFlags = %d", dirFlags);
-                    ALOGD("      -- paraDir = %d", paraDir);
-                    ALOGD("      -- run-count = %d", int(rc));
-#endif
-                    if (U_SUCCESS(status) && rc == 1) {
-                        // Normal case: one run, status is ok
-                        isRTL = (paraDir == 1);
-                        useSingleRun = true;
-                    } else if (!U_SUCCESS(status) || rc < 1) {
-                        ALOGW("Need to force to single run -- string = '%s',"
-                                " status = %d, rc = %d",
-                                String8(chars + start, count).string(), status, int(rc));
-                        isRTL = (paraDir == 1);
-                        useSingleRun = true;
-                    } else {
-                        int32_t end = start + count;
-                        for (size_t i = 0; i < size_t(rc); ++i) {
-                            int32_t startRun = -1;
-                            int32_t lengthRun = -1;
-                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
-
-                            if (startRun == -1 || lengthRun == -1) {
-                                // Something went wrong when getting the visual run, need to clear
-                                // already computed data before doing a single run pass
-                                ALOGW("Visual run is not valid");
-                                outGlyphs->clear();
-                                outAdvances->clear();
-                                outPos->clear();
-                                *outTotalAdvance = 0;
-                                isRTL = (paraDir == 1);
-                                useSingleRun = true;
-                                break;
-                            }
-
-                            if (startRun >= end) {
-                                continue;
-                            }
-                            int32_t endRun = startRun + lengthRun;
-                            if (endRun <= int32_t(start)) {
-                                continue;
-                            }
-                            if (startRun < int32_t(start)) {
-                                startRun = int32_t(start);
-                            }
-                            if (endRun > end) {
-                                endRun = end;
-                            }
-
-                            lengthRun = endRun - startRun;
-                            isRTL = (runDir == UBIDI_RTL);
-#if DEBUG_GLYPHS
-                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
-                                    i, startRun, lengthRun, isRTL);
-#endif
-                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
-                                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
-
-                        }
-                    }
-                } else {
-                    ALOGW("Cannot set Para");
-                    useSingleRun = true;
-                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
-                }
-                ubidi_close(bidi);
-            } else {
-                ALOGW("Cannot ubidi_open()");
-                useSingleRun = true;
-                isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
-            }
-        }
-
-        // Default single run case
-        if (useSingleRun){
-#if DEBUG_GLYPHS
-            ALOGD("Using a SINGLE BiDi Run "
-                    "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
-#endif
-            computeRunValues(paint, chars, start, count, contextCount, isRTL,
-                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
-        }
-
-#if DEBUG_GLYPHS
-        ALOGD("      -- Total returned glyphs-count = %d", outGlyphs->size());
-        ALOGD("******** ComputeValues -- end");
-#endif
-}
-
-#define HB_IsHighSurrogate(ucs) \
-    (((ucs) & 0xfc00) == 0xd800)
-
-#define HB_IsLowSurrogate(ucs) \
-    (((ucs) & 0xfc00) == 0xdc00)
-
-#ifndef HB_SurrogateToUcs4
-#define HB_SurrogateToUcs4(high, low) \
-    (((hb_codepoint_t)(high))<<10) + (low) - 0x35fdc00;
-#endif
-
-#define HB_InvalidCodePoint ~0u
-
-hb_codepoint_t
-utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter) {
-  const uint16_t v = chars[(*iter)++];
-  if (HB_IsHighSurrogate(v)) {
-    // surrogate pair
-    if (size_t(*iter) >= len) {
-      // the surrogate is incomplete.
-      return HB_InvalidCodePoint;
-    }
-    const uint16_t v2 = chars[(*iter)++];
-    if (!HB_IsLowSurrogate(v2)) {
-      // invalidate surrogate pair.
-      (*iter)--;
-      return HB_InvalidCodePoint;
-    }
-
-    return HB_SurrogateToUcs4(v, v2);
-  }
-
-  if (HB_IsLowSurrogate(v)) {
-    // this isn't a valid code point
-    return HB_InvalidCodePoint;
-  }
-
-  return v;
-}
-
-hb_codepoint_t
-utf16_to_code_point_prev(const uint16_t *chars, size_t len, ssize_t *iter) {
-  const uint16_t v = chars[(*iter)--];
-  if (HB_IsLowSurrogate(v)) {
-    // surrogate pair
-    if (*iter < 0) {
-      // the surrogate is incomplete.
-      return HB_InvalidCodePoint;
-    }
-    const uint16_t v2 = chars[(*iter)--];
-    if (!HB_IsHighSurrogate(v2)) {
-      // invalidate surrogate pair.
-      (*iter)++;
-      return HB_InvalidCodePoint;
-    }
-
-    return HB_SurrogateToUcs4(v2, v);
-  }
-
-  if (HB_IsHighSurrogate(v)) {
-    // this isn't a valid code point
-    return HB_InvalidCodePoint;
-  }
-
-  return v;
-}
-
-struct ScriptRun {
-    hb_script_t script;
-    size_t pos;
-    size_t length;
-};
-
-hb_script_t code_point_to_script(hb_codepoint_t codepoint) {
-    static hb_unicode_funcs_t* u;
-    if (!u) {
-        u = hb_icu_get_unicode_funcs();
-    }
-    return hb_unicode_script(u, codepoint);
-}
-
-bool
-hb_utf16_script_run_next(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
-  if (size_t(*iter) == len)
-    return false;
-
-  run->pos = *iter;
-  const uint32_t init_cp = utf16_to_code_point(chars, len, iter);
-  const hb_script_t init_script = code_point_to_script(init_cp);
-  hb_script_t current_script = init_script;
-  run->script = init_script;
-
-  for (;;) {
-    if (size_t(*iter) == len)
-      break;
-    const ssize_t prev_iter = *iter;
-    const uint32_t cp = utf16_to_code_point(chars, len, iter);
-    const hb_script_t script = code_point_to_script(cp);
-
-    if (script != current_script) {
-        /* BEGIN android-changed
-           The condition was not correct by doing "a == b == constant"
-           END android-changed */
-      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
-        // If we started off as inherited, we take whatever we can find.
-        run->script = script;
-        current_script = script;
-        continue;
-      } else if (script == HB_SCRIPT_INHERITED) {
-        continue;
-      } else {
-        *iter = prev_iter;
-        break;
-      }
-    }
-  }
-
-  if (run->script == HB_SCRIPT_INHERITED)
-    run->script = HB_SCRIPT_COMMON;
-
-  run->length = *iter - run->pos;
-  return true;
-}
-
-bool
-hb_utf16_script_run_prev(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
-  if (*iter == -1)
-    return false;
-
-  const size_t ending_index = *iter;
-  const uint32_t init_cp = utf16_to_code_point_prev(chars, len, iter);
-  const hb_script_t init_script = code_point_to_script(init_cp);
-  hb_script_t current_script = init_script;
-  run->script = init_script;
-  size_t break_iter = *iter;
-
-  for (;;) {
-    if (*iter < 0)
-      break;
-    const uint32_t cp = utf16_to_code_point_prev(chars, len, iter);
-    const hb_script_t script = code_point_to_script(cp);
-
-    if (script != current_script) {
-      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
-        // If we started off as inherited, we take whatever we can find.
-        run->script = script;
-        current_script = script;
-        // In cases of script1 + inherited + script2, always group the inherited
-        // with script1.
-        break_iter = *iter;
-        continue;
-      } else if (script == HB_SCRIPT_INHERITED) {
-        continue;
-      } else {
-        *iter = break_iter;
-        break;
-      }
-    } else {
-        break_iter = *iter;
-    }
-  }
-
-  if (run->script == HB_SCRIPT_INHERITED)
-    run->script = HB_SCRIPT_COMMON;
-
-  run->pos = *iter + 1;
-  run->length = ending_index - *iter;
-  return true;
-}
-
-
-static void logGlyphs(hb_buffer_t* buffer) {
-    unsigned int numGlyphs;
-    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
-    hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
-    ALOGD("         -- glyphs count=%d", numGlyphs);
-    for (size_t i = 0; i < numGlyphs; i++) {
-        ALOGD("         -- glyph[%d] = %d, cluster = %u, advance = %0.2f, offset.x = %0.2f, offset.y = %0.2f", i,
-                info[i].codepoint,
-                info[i].cluster,
-                HBFixedToFloat(positions[i].x_advance),
-                HBFixedToFloat(positions[i].x_offset),
-                HBFixedToFloat(positions[i].y_offset));
-    }
-}
-
-void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* contextChars,
-        size_t start, size_t count, size_t contextCount, bool isRTL,
-        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
-        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
-    if (!count) {
-        // We cannot shape an empty run.
-        return;
-    }
-
-    // To be filled in later
-    for (size_t i = 0; i < count; i++) {
-        outAdvances->add(0);
-    }
-
-    // Set the string properties
-    const UChar* chars = contextChars + start;
-
-    // Define shaping paint properties
-    mShapingPaint.setTextSize(paint->getTextSize());
-    float skewX = paint->getTextSkewX();
-    mShapingPaint.setTextSkewX(skewX);
-    mShapingPaint.setTextScaleX(paint->getTextScaleX());
-    mShapingPaint.setFlags(paint->getFlags());
-    mShapingPaint.setHinting(paint->getHinting());
-    mShapingPaint.setPaintOptionsAndroid(paint->getPaintOptionsAndroid());
-
-    // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
-    // into the shaperItem
-    ssize_t indexFontRun = isRTL ? count - 1 : 0;
-    jfloat totalAdvance = *outTotalAdvance;
-    ScriptRun run;  // relative to chars
-    while ((isRTL) ?
-            hb_utf16_script_run_prev(&run, chars, count, &indexFontRun):
-            hb_utf16_script_run_next(&run, chars, count, &indexFontRun)) {
-
-#if DEBUG_GLYPHS
-        ALOGD("-------- Start of Script Run --------");
-        ALOGD("Shaping Script Run with");
-        ALOGD("         -- isRTL = %d", isRTL);
-        ALOGD("         -- HB script = %c%c%c%c", HB_UNTAG(run.script));
-        ALOGD("         -- run.pos = %d", int(run.pos));
-        ALOGD("         -- run.length = %d", int(run.length));
-        ALOGD("         -- run = '%s'", String8(chars + run.pos, run.length).string());
-        ALOGD("         -- string = '%s'", String8(chars, count).string());
-#endif
-
-        hb_buffer_reset(mBuffer);
-        // Note: if we want to set unicode functions, etc., this is the place.
-        
-        hb_buffer_set_direction(mBuffer, isRTL ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
-        hb_buffer_set_script(mBuffer, run.script);
-        SkString langString = paint->getPaintOptionsAndroid().getLanguage().getTag();
-        hb_buffer_set_language(mBuffer, hb_language_from_string(langString.c_str(), -1));
-        hb_buffer_add_utf16(mBuffer, contextChars, contextCount, start + run.pos, run.length);
-
-        // Initialize Harfbuzz Shaper and get the base glyph count for offsetting the glyphIDs
-        // and shape the Font run
-        size_t glyphBaseCount = shapeFontRun(paint);
-        unsigned int numGlyphs;
-        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
-        hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(mBuffer, NULL);
-
-#if DEBUG_GLYPHS
-        ALOGD("Got from Harfbuzz");
-        ALOGD("         -- glyphBaseCount = %d", glyphBaseCount);
-        ALOGD("         -- num_glyph = %d", numGlyphs);
-        ALOGD("         -- isDevKernText = %d", paint->isDevKernText());
-        ALOGD("         -- initial totalAdvance = %f", totalAdvance);
-
-        logGlyphs(mBuffer);
-#endif
-
-        for (size_t i = 0; i < numGlyphs; i++) {
-            size_t cluster = info[i].cluster - start;
-            float xAdvance = HBFixedToFloat(positions[i].x_advance);
-            outAdvances->replaceAt(outAdvances->itemAt(cluster) + xAdvance, cluster);
-            jchar glyphId = info[i].codepoint + glyphBaseCount;
-            outGlyphs->add(glyphId);
-            float xo = HBFixedToFloat(positions[i].x_offset);
-            float yo = -HBFixedToFloat(positions[i].y_offset);
-
-            float xpos = totalAdvance + xo + yo * skewX;
-            float ypos = yo;
-            outPos->add(xpos);
-            outPos->add(ypos);
-            totalAdvance += xAdvance;
-
-            SkAutoGlyphCache autoCache(mShapingPaint, NULL, NULL);
-            const SkGlyph& metrics = autoCache.getCache()->getGlyphIDMetrics(glyphId);
-            outBounds->join(xpos + metrics.fLeft, ypos + metrics.fTop,
-                    xpos + metrics.fLeft + metrics.fWidth, ypos + metrics.fTop + metrics.fHeight);
-
-        }
-    }
-
-    *outTotalAdvance = totalAdvance;
-
-#if DEBUG_GLYPHS
-    ALOGD("         -- final totalAdvance = %f", totalAdvance);
-    ALOGD("-------- End of Script Run --------");
-#endif
-}
-
-/**
- * Return the first typeface in the logical change, starting with this typeface,
- * that contains the specified unichar, or NULL if none is found.
- */
-SkTypeface* TextLayoutShaper::typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
-        hb_script_t script) {
-    SkTypeface::Style currentStyle = SkTypeface::kNormal;
-    if (typeface) {
-        currentStyle = typeface->style();
-    }
-    typeface = SkCreateTypefaceForScript(script, currentStyle);
-#if DEBUG_GLYPHS
-    ALOGD("Using Harfbuzz Script %c%c%c%c, Style %d", HB_UNTAG(script), currentStyle);
-#endif
-    return typeface;
-}
-
-bool TextLayoutShaper::isComplexScript(hb_script_t script) {
-    switch (script) {
-    case HB_SCRIPT_COMMON:
-    case HB_SCRIPT_GREEK:
-    case HB_SCRIPT_CYRILLIC:
-    case HB_SCRIPT_HANGUL:
-    case HB_SCRIPT_INHERITED:
-    case HB_SCRIPT_HAN:
-    case HB_SCRIPT_KATAKANA:
-    case HB_SCRIPT_HIRAGANA:
-        return false;
-    default:
-        return true;
-    }
-}
-
-size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint) {
-    // Update Harfbuzz Shaper
-
-    SkTypeface* typeface = paint->getTypeface();
-
-    // Get the glyphs base count for offsetting the glyphIDs returned by Harfbuzz
-    // This is needed as the Typeface used for shaping can be not the default one
-    // when we are shaping any script that needs to use a fallback Font.
-    // If we are a "common" script we dont need to shift
-    size_t baseGlyphCount = 0;
-    hb_codepoint_t firstUnichar = 0;
-    if (isComplexScript(hb_buffer_get_script(mBuffer))) {
-        unsigned int numGlyphs;
-        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
-        for (size_t i = 0; i < numGlyphs; i++) {
-            firstUnichar = info[i].codepoint;
-            if (firstUnichar != ' ') {
-                break;
-            }
-        }
-        baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
-    }
-
-    SkTypeface* scriptTypeface = NULL;
-    if (baseGlyphCount != 0) {
-        scriptTypeface = typefaceForScript(paint, typeface,
-            hb_buffer_get_script(mBuffer));
-#if DEBUG_GLYPHS
-        ALOGD("Using Default Typeface for script %c%c%c%c",
-            HB_UNTAG(hb_buffer_get_script(mBuffer)));
-#endif
-    }
-    if (scriptTypeface) {
-        typeface = scriptTypeface;
-    } else {
-        baseGlyphCount = 0;
-        if (typeface) {
-            SkSafeRef(typeface);
-        } else {
-            typeface = SkTypeface::CreateFromName(NULL, SkTypeface::kNormal);
-#if DEBUG_GLYPHS
-            ALOGD("Using Default Typeface (normal style)");
-#endif
-        }
-    }
-
-    mShapingPaint.setTypeface(typeface);
-    hb_face_t* face = referenceCachedHBFace(typeface);
-
-    float sizeY = paint->getTextSize();
-    float sizeX = sizeY * paint->getTextScaleX();
-    hb_font_t* font = createFont(face, &mShapingPaint, sizeX, sizeY);
-    hb_face_destroy(face);
-
-#if DEBUG_GLYPHS
-    ALOGD("Run typeface = %p, uniqueID = %d, face = %p",
-            typeface, typeface->uniqueID(), face);
-#endif
-    SkSafeUnref(typeface);
-
-    hb_shape(font, mBuffer, NULL, 0);
-    hb_font_destroy(font);
-
-    mShapingPaint.setTypeface(paint->getTypeface());
-    return baseGlyphCount;
-}
-
-hb_face_t* TextLayoutShaper::referenceCachedHBFace(SkTypeface* typeface) {
-    SkFontID fontId = typeface->uniqueID();
-    ssize_t index = mCachedHBFaces.indexOfKey(fontId);
-    if (index >= 0) {
-        return hb_face_reference(mCachedHBFaces.valueAt(index));
-    }
-    // TODO: destroy function
-    hb_face_t* face = hb_face_create_for_tables(harfbuzzSkiaReferenceTable, typeface, NULL);
-#if DEBUG_GLYPHS
-    ALOGD("Created HB_NewFace %p from paint typeface = %p", face, typeface);
-#endif
-    mCachedHBFaces.add(fontId, face);
-    return hb_face_reference(face);
-}
-
-void TextLayoutShaper::purgeCaches() {
-    size_t cacheSize = mCachedHBFaces.size();
-    for (size_t i = 0; i < cacheSize; i++) {
-        hb_face_destroy(mCachedHBFaces.valueAt(i));
-    }
-    mCachedHBFaces.clear();
-}
-
-TextLayoutEngine::TextLayoutEngine() {
-    mShaper = new TextLayoutShaper();
-#if USE_TEXT_LAYOUT_CACHE
-    mTextLayoutCache = new TextLayoutCache(mShaper);
-#else
-    mTextLayoutCache = NULL;
-#endif
-}
-
-TextLayoutEngine::~TextLayoutEngine() {
-    delete mTextLayoutCache;
-    delete mShaper;
-}
-
-sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
-        jint start, jint count, jint contextCount, jint dirFlags) {
-    sp<TextLayoutValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    value = mTextLayoutCache->getValue(paint, text, start, count,
-            contextCount, dirFlags);
-    if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text + start, count).string());
-    }
-#else
-    value = new TextLayoutValue(count);
-    mShaper->computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
-#endif
-    return value;
-}
-
-void TextLayoutEngine::purgeCaches() {
-#if USE_TEXT_LAYOUT_CACHE
-    mTextLayoutCache->purgeCaches();
-#if DEBUG_GLYPHS
-    ALOGD("Purged TextLayoutEngine caches");
-#endif
-#endif
-}
-
-
-} // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
deleted file mode 100644
index 54704ec..0000000
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef ANDROID_TEXT_LAYOUT_CACHE_H
-#define ANDROID_TEXT_LAYOUT_CACHE_H
-
-#include "RtlProperties.h"
-
-#include <stddef.h>
-#include <utils/threads.h>
-#include <utils/String16.h>
-#include <utils/LruCache.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Singleton.h>
-
-#include <SkAutoKern.h>
-#include <SkPaint.h>
-#include <SkTemplates.h>
-#include <SkTypeface.h>
-#include <SkUtils.h>
-
-#include <unicode/ubidi.h>
-#include <unicode/unistr.h>
-
-#include <hb.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#define UNICODE_NOT_A_CHAR              0xffff
-#define UNICODE_ZWSP                    0x200b
-#define UNICODE_FIRST_LOW_SURROGATE     0xdc00
-#define UNICODE_FIRST_HIGH_SURROGATE    0xd800
-#define UNICODE_FIRST_PRIVATE_USE       0xe000
-#define UNICODE_FIRST_RTL_CHAR          0x0590
-
-// Temporary buffer size
-#define CHAR_BUFFER_SIZE 80
-
-// Converts a number of mega-bytes into bytes
-#define MB(s) s * 1024 * 1024
-
-// Define the default cache size in Mb
-#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f
-
-// Define the interval in number of cache hits between two statistics dump
-#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
-
-namespace android {
-
-/**
- * TextLayoutCacheKey is the Cache key
- */
-class TextLayoutCacheKey {
-public:
-    TextLayoutCacheKey();
-
-    TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
-            size_t contextCount, int dirFlags);
-
-    TextLayoutCacheKey(const TextLayoutCacheKey& other);
-
-    /**
-     * Get the size of the Cache key.
-     */
-    size_t getSize() const;
-
-    static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
-
-    inline const UChar* getText() const { return textCopy.string(); }
-
-    bool operator==(const TextLayoutCacheKey& other) const {
-        return compare(*this, other) == 0;
-    }
-
-    bool operator!=(const TextLayoutCacheKey& other) const {
-        return compare(*this, other) != 0;
-    }
-
-    hash_t hash() const;
-private:
-    String16 textCopy;
-    size_t start;
-    size_t count;
-    size_t contextCount;
-    int dirFlags;
-    SkTypeface* typeface;
-    SkScalar textSize;
-    SkScalar textSkewX;
-    SkScalar textScaleX;
-    uint32_t flags;
-    SkPaint::Hinting hinting;
-    SkPaintOptionsAndroid paintOpts;
-
-}; // TextLayoutCacheKey
-
-inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
-    return TextLayoutCacheKey::compare(lhs, rhs) < 0;
-}
-
-inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
-    return TextLayoutCacheKey::compare(lhs, rhs);
-}
-
-inline hash_t hash_type(const TextLayoutCacheKey& key) {
-    return key.hash();
-}
-
-/*
- * TextLayoutValue is the Cache value
- */
-class TextLayoutValue : public RefBase {
-public:
-    TextLayoutValue(size_t contextCount);
-
-    void setElapsedTime(uint32_t time);
-    uint32_t getElapsedTime();
-
-    inline const jfloat* getAdvances() const { return mAdvances.array(); }
-    inline size_t getAdvancesCount() const { return mAdvances.size(); }
-    inline jfloat getTotalAdvance() const { return mTotalAdvance; }
-    inline const SkRect& getBounds() const { return mBounds; }
-    inline const jchar* getGlyphs() const { return mGlyphs.array(); }
-    inline size_t getGlyphsCount() const { return mGlyphs.size(); }
-    inline const jfloat* getPos() const { return mPos.array(); }
-    inline size_t getPosCount() const { return mPos.size(); }
-
-    /**
-     * Advances vector
-     */
-    Vector<jfloat> mAdvances;
-
-    /**
-     * Total number of advances
-     */
-    jfloat mTotalAdvance;
-
-    /**
-     * Bounds containing all glyphs
-     */
-    SkRect mBounds;
-
-    /**
-     * Glyphs vector
-     */
-    Vector<jchar> mGlyphs;
-
-    /**
-     * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText)
-     */
-    Vector<jfloat> mPos;
-
-    /**
-     * Get the size of the Cache entry
-     */
-    size_t getSize() const;
-
-private:
-    /**
-     * Time for computing the values (in milliseconds)
-     */
-    uint32_t mElapsedTime;
-
-}; // TextLayoutCacheValue
-
-/**
- * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
- */
-class TextLayoutShaper {
-public:
-    TextLayoutShaper();
-    virtual ~TextLayoutShaper();
-
-    void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, int dirFlags);
-
-    void purgeCaches();
-
-private:
-    /**
-     * Harfbuzz buffer for shaping
-     */
-    hb_buffer_t* mBuffer;
-
-    /**
-     * Skia Paint used for shaping
-     */
-    SkPaint mShapingPaint;
-
-    /**
-     * Cache of Harfbuzz faces
-     */
-    KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
-
-    SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
-        hb_script_t script);
-
-    size_t shapeFontRun(const SkPaint* paint);
-
-    void computeValues(const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, int dirFlags,
-            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
-            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
-
-    void computeRunValues(const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, bool isRTL,
-            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
-            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
-
-    SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
-    hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
-
-    bool isComplexScript(hb_script_t script);
-}; // TextLayoutShaper
-
-/**
- * Cache of text layout information.
- */
-class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
-{
-public:
-    TextLayoutCache(TextLayoutShaper* shaper);
-
-    ~TextLayoutCache();
-
-    bool isInitialized() {
-        return mInitialized;
-    }
-
-    /**
-     * Used as a callback when an entry is removed from the cache
-     * Do not invoke directly
-     */
-    void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
-
-    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount, jint dirFlags);
-
-    /**
-     * Clear the cache
-     */
-    void purgeCaches();
-
-private:
-    TextLayoutShaper* mShaper;
-    Mutex mLock;
-    bool mInitialized;
-
-    LruCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
-
-    uint32_t mSize;
-    uint32_t mMaxSize;
-
-    uint32_t mCacheHitCount;
-    uint64_t mNanosecondsSaved;
-
-    uint64_t mCacheStartTime;
-
-    RtlDebugLevel mDebugLevel;
-    bool mDebugEnabled;
-
-    /*
-     * Class initialization
-     */
-    void init();
-
-    /**
-     * Dump Cache statistics
-     */
-    void dumpCacheStats();
-
-}; // TextLayoutCache
-
-/**
- * The TextLayoutEngine is reponsible for computing TextLayoutValues
- */
-class TextLayoutEngine : public Singleton<TextLayoutEngine> {
-public:
-    TextLayoutEngine();
-    virtual ~TextLayoutEngine();
-
-    /**
-     * Note: this method currently does a defensive copy of the text argument, in case
-     * there is concurrent mutation of it. The contract may change, and may in the
-     * future require the caller to guarantee that the contents will not change during
-     * the call. Be careful of this when doing optimization.
-     **/
-    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount, jint dirFlags);
-
-    void purgeCaches();
-
-private:
-    TextLayoutCache* mTextLayoutCache;
-    TextLayoutShaper* mShaper;
-}; // TextLayoutEngine
-
-} // namespace android
-#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
-
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index b20c246..cf4e838 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -27,44 +27,10 @@
 
 using namespace android;
 
-class AutoJavaStringToUTF8 {
-public:
-    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str)
-    {
-        fCStr = env->GetStringUTFChars(str, NULL);
-    }
-    ~AutoJavaStringToUTF8()
-    {
-        fEnv->ReleaseStringUTFChars(fJStr, fCStr);
-    }
-    const char* c_str() const { return fCStr; }
-
-private:
-    JNIEnv*     fEnv;
-    jstring     fJStr;
-    const char* fCStr;
-};
-
-static jlong Typeface_create(JNIEnv* env, jobject, jstring name,
-                             jint styleHandle) {
-    SkTypeface::Style style = static_cast<SkTypeface::Style>(styleHandle);
-    TypefaceImpl* face = NULL;
-
-    if (NULL != name) {
-        AutoJavaStringToUTF8    str(env, name);
-        face = TypefaceImpl_createFromName(str.c_str(), style);
-    }
-
-    // return the default font at the best style if no exact match exists
-    if (NULL == face) {
-        face = TypefaceImpl_createFromName(NULL, style);
-    }
-    return reinterpret_cast<jlong>(face);
-}
-
 static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
     TypefaceImpl* family = reinterpret_cast<TypefaceImpl*>(familyHandle);
     TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
+    // TODO: the following logic shouldn't be necessary, the above should always succeed.
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
         face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
@@ -72,9 +38,6 @@
     for (int i = 0; NULL == face && i < 4; i++) {
         face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)i);
     }
-    if (NULL == face) {
-        face = TypefaceImpl_createFromName(NULL, (SkTypeface::Style)style);
-    }
     return reinterpret_cast<jlong>(face);
 }
 
@@ -88,33 +51,6 @@
     return TypefaceImpl_getStyle(face);
 }
 
-static jlong Typeface_createFromAsset(JNIEnv* env, jobject,
-                                      jobject jassetMgr,
-                                      jstring jpath) {
-    NPE_CHECK_RETURN_ZERO(env, jassetMgr);
-    NPE_CHECK_RETURN_ZERO(env, jpath);
-
-    AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
-    if (NULL == mgr) {
-        return NULL;
-    }
-
-    AutoJavaStringToUTF8 str(env, jpath);
-    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
-    if (NULL == asset) {
-        return NULL;
-    }
-
-    return reinterpret_cast<jlong>(TypefaceImpl_createFromAsset(asset));
-}
-
-static jlong Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
-    NPE_CHECK_RETURN_ZERO(env, jpath);
-
-    AutoJavaStringToUTF8 str(env, jpath);
-    return reinterpret_cast<jlong>(TypefaceImpl_createFromFile(str.c_str()));
-}
-
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
     ScopedLongArrayRO families(env, familyArray);
     return reinterpret_cast<jlong>(TypefaceImpl_createFromFamilies(families.get(), families.size()));
@@ -128,14 +64,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gTypefaceMethods[] = {
-    { "nativeCreate",        "(Ljava/lang/String;I)J", (void*)Typeface_create },
     { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
-    { "nativeCreateFromAsset",    "(Landroid/content/res/AssetManager;Ljava/lang/String;)J",
-                                           (void*)Typeface_createFromAsset },
-    { "nativeCreateFromFile",     "(Ljava/lang/String;)J",
-                                           (void*)Typeface_createFromFile },
     { "nativeCreateFromArray",    "([J)J",
                                            (void*)Typeface_createFromArray },
     { "nativeSetDefault",         "(J)V",   (void*)Typeface_setDefault },
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
index 1800d0c..7767b8d 100644
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -27,22 +27,18 @@
 #include "SkStream.h"
 #include "SkTypeface.h"
 
-#ifdef USE_MINIKIN
 #include <vector>
 #include <minikin/FontCollection.h>
 #include <minikin/FontFamily.h>
 #include <minikin/Layout.h>
 #include "SkPaint.h"
 #include "MinikinSkia.h"
-#endif
 
 #include "TypefaceImpl.h"
 #include "Utils.h"
 
 namespace android {
 
-#ifdef USE_MINIKIN
-
 // Any weight greater than or equal to this is considered "bold" for
 // legacy API.
 static const int kBoldThreshold = 6;
@@ -135,30 +131,6 @@
     return result;
 }
 
-// Delete when removing USE_MINIKIN ifdef
-TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
-    SkTypeface* face = SkTypeface::CreateFromName(name, style);
-    return createFromSkTypeface(face);
-}
-
-// Delete when removing USE_MINIKIN ifdef
-TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
-    SkTypeface* face = SkTypeface::CreateFromFile(filename);
-    return createFromSkTypeface(face);
-}
-
-// Delete when removing USE_MINIKIN ifdef
-TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
-    SkStream* stream = new AssetStreamAdaptor(asset,
-                                              AssetStreamAdaptor::kYes_OwnAsset,
-                                              AssetStreamAdaptor::kYes_HasMemoryBase);
-    SkTypeface* face = SkTypeface::CreateFromStream(stream);
-    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
-    // need to unref it here or it won't be freed later on
-    stream->unref();
-    return createFromSkTypeface(face);
-}
-
 TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
     std::vector<FontFamily *>familyVec;
     for (size_t i = 0; i < size; i++) {
@@ -202,52 +174,4 @@
     gDefaultTypeface = face;
 }
 
-#else  // USE_MINIKIN
-
-/* Just use SkTypeface instead. */
-
-typedef SkTypeface TypefaceImpl;
-
-TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
-    return SkTypeface::CreateFromTypeface(src, style);
-}
-
-TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
-    return SkTypeface::CreateFromName(name, style);
-}
-
-TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
-    return SkTypeface::CreateFromFile(filename);
-}
-
-TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
-    SkStream* stream = new AssetStreamAdaptor(asset,
-                                              AssetStreamAdaptor::kYes_OwnAsset,
-                                              AssetStreamAdaptor::kYes_HasMemoryBase);
-    SkTypeface* face = SkTypeface::CreateFromStream(stream);
-    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
-    // need to unref it here or it won't be freed later on
-    stream->unref();
-
-    return face;
-}
-
-TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
-    // Should never be called in non-Minikin builds
-    return 0;
-}
-
-void TypefaceImpl_unref(TypefaceImpl* face) {
-    SkSafeUnref(face);
-}
-
-int TypefaceImpl_getStyle(TypefaceImpl* face) {
-    return face->style();
-}
-
-void TypefaceImpl_setDefault(TypefaceImpl* face) {
-}
-
-#endif  // USE_MINIKIN
-
 }
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index 4e92bce..12b3403 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -22,13 +22,10 @@
 #include "SkTypeface.h"
 #include <androidfw/AssetManager.h>
 
-#ifdef USE_MINIKIN
 #include <minikin/FontCollection.h>
-#endif
 
 namespace android {
 
-#ifdef USE_MINIKIN
 struct TypefaceImpl {
     FontCollection *fFontCollection;
     FontStyle fStyle;
@@ -41,18 +38,9 @@
 // TODO: when #ifdef USE_MINIKIN is removed, move to member functions.
 
 TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src);
-#else
-typedef SkTypeface TypefaceImpl;
-#endif
 
 TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style);
 
-TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style);
-
-TypefaceImpl* TypefaceImpl_createFromFile(const char* filename);
-
-TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset);
-
 // When we remove the USE_MINIKIN ifdef, probably a good idea to move the casting
 // (from jlong to FontFamily*) to the caller in Typeface.cpp.
 TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size);
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index bc5e1b3..6f89800 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -214,7 +214,8 @@
     return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
 }
 
-static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname,
+        jobject info)
 {
     return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
 }
@@ -252,14 +253,14 @@
     }
 }
 
-static void android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
+static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
 {
-    setNetworkForProcess(netId);
+    return (jboolean) !setNetworkForProcess(netId);
 }
 
-static void android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz)
+static jboolean android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz)
 {
-    setNetworkForProcess(NETID_UNSET);
+    return (jboolean) !setNetworkForProcess(NETID_UNSET);
 }
 
 static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz)
@@ -267,19 +268,21 @@
     return getNetworkForProcess();
 }
 
-static void android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, jint netId)
+static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz,
+        jint netId)
 {
-    setNetworkForResolv(netId);
+    return (jboolean) !setNetworkForResolv(netId);
 }
 
-static void android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz)
+static jboolean android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz)
 {
-    setNetworkForResolv(NETID_UNSET);
+    return (jboolean) !setNetworkForResolv(NETID_UNSET);
 }
 
-static void android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, jint netId)
+static jboolean android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
+        jint netId)
 {
-    setNetworkForSocket(netId, socket);
+    return (jboolean) !setNetworkForSocket(netId, socket);
 }
 
 // ----------------------------------------------------------------------------
@@ -299,12 +302,12 @@
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
     { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
-    { "bindProcessToNetwork", "(I)V", (void*) android_net_utils_bindProcessToNetwork },
+    { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
     { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
-    { "unbindProcessToNetwork", "()V", (void*) android_net_utils_unbindProcessToNetwork },
-    { "bindProcessToNetworkForHostResolution", "(I)V", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
-    { "unbindProcessToNetworkForHostResolution", "()V", (void*) android_net_utils_unbindProcessToNetworkForHostResolution },
-    { "bindSocketToNetwork", "(II)V", (void*) android_net_utils_bindSocketToNetwork },
+    { "unbindProcessToNetwork", "()Z", (void*) android_net_utils_unbindProcessToNetwork },
+    { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
+    { "unbindProcessToNetworkForHostResolution", "()Z", (void*) android_net_utils_unbindProcessToNetworkForHostResolution },
+    { "bindSocketToNetwork", "(II)Z", (void*) android_net_utils_bindSocketToNetwork },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2a1fd1b..b74bf0f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -43,14 +43,9 @@
 #include <RenderNode.h>
 #include <CanvasProperty.h>
 
-#ifdef USE_MINIKIN
 #include <minikin/Layout.h>
 #include "MinikinSkia.h"
 #include "MinikinUtils.h"
-#endif
-
-#include <TextLayout.h>
-#include <TextLayoutCache.h>
 
 namespace android {
 
@@ -569,23 +564,6 @@
 // Text
 // ----------------------------------------------------------------------------
 
-// TODO: this is moving to MinikinUtils, remove with USE_MINIKIN ifdef
-static float xOffsetForTextAlign(SkPaint* paint, float totalAdvance) {
-    switch (paint->getTextAlign()) {
-        case SkPaint::kCenter_Align:
-            return -totalAdvance / 2.0f;
-            break;
-        case SkPaint::kRight_Align:
-            return -totalAdvance;
-            break;
-        default:
-            break;
-    }
-    return 0;
-}
-
-#ifdef USE_MINIKIN
-
 class RenderTextFunctor {
 public:
     RenderTextFunctor(const Layout& layout, DisplayListRenderer* renderer, jfloat x, jfloat y,
@@ -632,38 +610,16 @@
     delete[] glyphs;
     delete[] pos;
 }
-#endif
 
 static void renderText(DisplayListRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
-#ifdef USE_MINIKIN
     Layout layout;
     std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
     layout.doLayout(text, 0, count, count, css);
-    x += xOffsetForTextAlign(paint, layout.getAdvance());
+    x += MinikinUtils::xOffsetForTextAlign(paint, layout);
     renderTextLayout(renderer, &layout, x, y, paint);
-#else
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, bidiFlags);
-    if (value == NULL) {
-        return;
-    }
-    const jchar* glyphs = value->getGlyphs();
-    size_t glyphsCount = value->getGlyphsCount();
-    jfloat totalAdvance = value->getTotalAdvance();
-    x += xOffsetForTextAlign(paint, totalAdvance);
-    const float* positions = value->getPos();
-    int bytesCount = glyphsCount * sizeof(jchar);
-    const SkRect& r = value->getBounds();
-    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);
-    bounds.translate(x, y);
-
-    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
-            x, y, positions, paint, totalAdvance, bounds);
-#endif
 }
 
-#ifdef USE_MINIKIN
 class RenderTextOnPathFunctor {
 public:
     RenderTextOnPathFunctor(const Layout& layout, DisplayListRenderer* renderer, float hOffset,
@@ -688,12 +644,10 @@
     SkPaint* paint;
     SkPath* path;
 };
-#endif
 
 static void renderTextOnPath(DisplayListRenderer* renderer, const jchar* text, int count,
         SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint,
         TypefaceImpl* typeface) {
-#ifdef USE_MINIKIN
     Layout layout;
     std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
     layout.doLayout(text, 0, count, count, css);
@@ -704,48 +658,16 @@
     RenderTextOnPathFunctor f(layout, renderer, hOffset, vOffset, paint, path);
     MinikinUtils::forFontRun(layout, paint, f);
     paint->setTextAlign(align);
-#else
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, bidiFlags);
-    if (value == NULL) {
-        return;
-    }
-    const jchar* glyphs = value->getGlyphs();
-    size_t glyphsCount = value->getGlyphsCount();
-    int bytesCount = glyphsCount * sizeof(jchar);
-    renderer->drawTextOnPath((const char*) glyphs, bytesCount, glyphsCount, path,
-            hOffset, vOffset, paint);
-#endif
 }
 
 static void renderTextRun(DisplayListRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
-#ifdef USE_MINIKIN
     Layout layout;
     std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
     layout.doLayout(text, start, count, contextCount, css);
-    x += xOffsetForTextAlign(paint, layout.getAdvance());
+    x += MinikinUtils::xOffsetForTextAlign(paint, layout);
     renderTextLayout(renderer, &layout, x, y, paint);
-#else
-    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, start, count, contextCount, bidiFlags);
-    if (value == NULL) {
-        return;
-    }
-    const jchar* glyphs = value->getGlyphs();
-    size_t glyphsCount = value->getGlyphsCount();
-    jfloat totalAdvance = value->getTotalAdvance();
-    x += xOffsetForTextAlign(paint, totalAdvance);
-    const float* positions = value->getPos();
-    int bytesCount = glyphsCount * sizeof(jchar);
-    const SkRect& r = value->getBounds();
-    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);
-    bounds.translate(x, y);
-
-    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
-            x, y, positions, paint, totalAdvance, bounds);
-#endif
 }
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 3ffde2d..6ba22bf 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -456,16 +456,9 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
     renderNode->addAnimator(animator);
+    animator->start();
 }
 
-static void android_view_RenderNode_removeAnimator(JNIEnv* env, jobject clazz,
-        jlong renderNodePtr, jlong animatorPtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
-    renderNode->removeAnimator(animator);
-}
-
-
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -546,7 +539,6 @@
     { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
 
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
-    { "nRemoveAnimator",           "(JJ)V", (void*) android_view_RenderNode_removeAnimator },
 #endif
 };
 
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index d689864..de3dd16 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -149,6 +149,11 @@
     animator->setInterpolator(interpolator);
 }
 
+static void cancel(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    animator->cancel();
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -168,6 +173,7 @@
     { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
     { "nGetStartDelay", "(J)J", (void*) getStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
+    { "nCancel", "(J)V", (void*) cancel },
 #endif
 };
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6e92b07..db02279 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -463,7 +463,7 @@
     <string name="user_owner_label">Personal apps</string>
 
     <!-- Label for a corporate profile in the intent forwarding app. -->
-    <string name="managed_profile_label">Android Work</string>
+    <string name="managed_profile_label">Work</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index cac6b93..ff2c8f0 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -20,8 +20,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.test.InstrumentationTestCase;
 
 import com.google.android.collect.Lists;
@@ -63,11 +65,11 @@
 
         setScorers(package1, package2, package3);
 
-        Iterator<String> result =
+        Iterator<NetworkScorerAppData> result =
                 NetworkScorerAppManager.getAllValidScorers(mMockContext).iterator();
 
         assertTrue(result.hasNext());
-        assertEquals("package1", result.next());
+        assertEquals("package1", result.next().mPackageName);
 
         assertFalse(result.hasNext());
     }
@@ -93,6 +95,7 @@
         ResolveInfo resolveInfo = new ResolveInfo();
         resolveInfo.activityInfo = new ActivityInfo();
         resolveInfo.activityInfo.packageName = packageName;
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
         if (hasReceiverPermission) {
             resolveInfo.activityInfo.permission = permission.BROADCAST_SCORE_NETWORKS;
         }
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
index d850c7c..9252270 100644
--- a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -20,6 +20,7 @@
 import android.graphics.RectF;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.CursorAnchorInfo.Builder;
 
@@ -81,7 +82,7 @@
         assertEquals(SELECTION_START, info.getSelectionStart());
         assertEquals(SELECTION_END, info.getSelectionEnd());
         assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
-        assertEquals(COMPOSING_TEXT, info.getComposingText());
+        assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText()));
         assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
         assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
         assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
@@ -97,7 +98,7 @@
         assertEquals(SELECTION_START, info2.getSelectionStart());
         assertEquals(SELECTION_END, info2.getSelectionEnd());
         assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
-        assertEquals(COMPOSING_TEXT, info2.getComposingText());
+        assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText()));
         assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
         assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
         assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
@@ -110,12 +111,12 @@
         assertEquals(info, info2);
         assertEquals(info.hashCode(), info2.hashCode());
 
-        // Make sure that object can be marshalled via {@link Parsel}.
+        // Make sure that object can be marshaled via {@link Parsel}.
         final CursorAnchorInfo info3 = cloneViaParcel(info2);
         assertEquals(SELECTION_START, info3.getSelectionStart());
         assertEquals(SELECTION_END, info3.getSelectionEnd());
         assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
-        assertEquals(COMPOSING_TEXT, info3.getComposingText());
+        assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText()));
         assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
         assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
         assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
diff --git a/docs/html/design/media/wear/fitness.png b/docs/html/design/media/wear/fitness.png
new file mode 100644
index 0000000..18ae969
--- /dev/null
+++ b/docs/html/design/media/wear/fitness.png
Binary files differ
diff --git a/docs/html/design/wear/structure.jd b/docs/html/design/wear/structure.jd
index f5ed49d..67b218a 100644
--- a/docs/html/design/wear/structure.jd
+++ b/docs/html/design/wear/structure.jd
@@ -97,9 +97,6 @@
 
 <h2 id="Custom">Breaking out of the card (with custom layouts)</h2>
 
-<p>There are some things you can’t do on a card. Swiping in many directions on a map or a joystick are a few examples. In those cases it might be good idea to momentarily go full screen.</p>
-
-
 <a class="notice-developers" href="{@docRoot}training/wearables/apps/index.html">
   <div>
     <h3>Developer Docs</h3>
@@ -107,6 +104,8 @@
   </div>
 </a>
 
+<p>There are some things you can’t do on a card. Swiping in many directions on a map or a joystick are a few examples. In those cases it might be good idea to momentarily go full screen.</p>
+
 <img src="{@docRoot}design/media/wear/customlayout.png" alt="" width="760px" />
 
 <h3>When to go full screen</h3>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index f992bf9..2e99194 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -110,7 +110,7 @@
 href="{@docRoot}">developer.android.com</a>. These API elements are
 formatted in {@code code style} in this document (without hyperlinks). For the
 preliminary API documentation for these elements, download the <a
-href="{@docRoot}preview/l-developer-preview-reference.zip">preview
+href="http://storage.googleapis.com/androiddevelopers/preview/l-developer-preview-reference.zip">preview
 reference</a>.</p>
 
 <h2 id="Behaviors">Important Behavior Changes</h2>
diff --git a/docs/html/preview/google-play-services-wear.html b/docs/html/preview/google-play-services-wear.html
index ff43757..84647b7 100644
--- a/docs/html/preview/google-play-services-wear.html
+++ b/docs/html/preview/google-play-services-wear.html
@@ -38,30 +38,29 @@
 <p>If you attended Google I/O, your registered Google account is automatically whitelisted for
 these preview resources. You're done! Head to Step 2.</p>
 
-<p><stong><em>If you didn't attend Google I/O</em></strong> or want to use a different account,
-click following link to
-<a href="https://groups.google.com/group/io14androidweardev/subscribe" target="_blank">join
-the Google Group</a> and get whitelisted.</p>
+<p><strong><em>If you didn't attend Google I/O</em></strong> or want to use a different account,
+click following link to  and get whitelisted.</p>
+
+<a style="font-size:24px" href="https://groups.google.com/group/io14androidweardev/subscribe" target="_blank">
+Join the Preview Group</a>
 
 <h2 style="margin-bottom: 0px;">2. Download Required Apps</h2><hr>
-<p>You'll need the following apps to get the most out of Android Wear:</p>
+<p>You'll need the following apps to get the most out of Android Wear. You must be whitelisted
+in the Preview Group above and you must install these apps in this exact order:</p>
 
-<ul>
+<ol>
 <li><a href="https://play.google.com/apps/testing/com.google.android.gms">Google Play services</a>:
 Allows your Android Wear device to communicate with your handheld device. This is required to
 use the Android Wear app and other apps listed below.</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.android.googlequicksearchbox">Google
+  Search</a>: Enables searches from Android Wear</li>
   <li><a href="https://play.google.com/apps/testing/com.google.android.wearable.app">Android Wear
   Companion</a>: The app for pairing a handheld to a wearable and providing syncing of
   notifications and data
   </li>
-  <li><a href="https://play.google.com/apps/testing/com.google.android.googlequicksearchbox">Google
-  Search</a>: Enables searches from Android Wear</li>
-  <li><a href="https://play.google.com/apps/testing/com.google.android.keep">Google Keep</a>:
-  Supports the "Take a note" command</li>
-  <li><a href="https://play.google.com/apps/testing/com.google.samples.apps.iosched">Google I/O
-  2014</a>:
-  Supports session feedback from Android Wear</li>
- </ul>
+  <p class="note"><b>Note:</b> After becoming a tester, it can take up to 1 hour to get access to
+  the preview versions of these apps.</p>
+ </ol>
 
 <p>To obtain these apps from Google Play, click each app link above and follow these instructions,
 preferably from your mobile browser:</p>
@@ -72,9 +71,22 @@
  <li>Click the <b>Download &lt;app name&gt; from the Play Store</b> link to go to Google Play
  Store download page to get the app. The
  following screenshot shows how the opt-in process looks like:
-<img style="margin-top:40px" src="/preview/images/opt-in.png"></li>
+<img style="margin-top:40px" src="/preview/images/opt-in.png" /></li>
 </ol>
-<h2 style="margin-bottom: 0px;">3. Start Building</h2><hr>
+
+<h2>3. Download Optional Apps</h2>
+<p>Please join the Test Group and install the following apps to enhance your Android Wear experience:
+</p>
+
+<ol>
+  <li><a href="https://play.google.com/apps/testing/com.google.android.keep">Google Keep</a>:
+  Supports the "Take a note" command</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.samples.apps.iosched">Google I/O
+  2014</a>:
+  Supports session feedback from Android Wear</li>
+  </ol>
+
+<h2 style="margin-bottom: 0px;">4. Start Building</h2><hr>
 
 <p>The Google Play services SDK is required if you want to sync and send data between wearable
 and handheld devices. To get the new SDK that is compatible with the Google Play services
@@ -82,7 +94,8 @@
 
 <p class="note"><b>Note:</b> Android Studio is required for Wear development.</p>
 <ol>
-  <li>Start AVD Manager.</li>
+  <li><a href="/sdk/installing/studio.html">Download and install Android Studio</a></li>
+  <li>Start SDK Manager.</li>
   <li>Update the Android SDK Tools and Platform-tools to versions 23 and 20 respectively.</li>
   <li>Click <b>Tools > Manage Add-on Sites > User Defined Sites</b>.</li>
   <li>Click <b>New</b>, enter
@@ -91,14 +104,13 @@
   <li>Click Close. You should now see new emulator images that support this preview
   release of Google Play services and the Google Play services client libraries you need to
   start developing.</li>
-  <li><a href="{@docRoot}preview/google-play-services-preview.zip">Download</a> the Google Play
+  <li><a href="http://storage.googleapis.com/androiddevelopers/preview/google-play-services-preview.zip">Download</a> the Google Play
   services reference documentation for this preview release.</li>.
 </ol>
 
-<p>When you're done here, check out the <a href="{@docRoot}training/building-wearables">Building Apps for Wearables</a>
+<p>When you're done here, check out the <a href="/training/building-wearables.html">Building Apps for Wearables</a>
 training classes for information on how to build for Wear.</p>
 
-    </div>
 </div> <!-- end jd-content -->
 </div><!-- end doc-content -->
 </div> <!-- end body-content -->
diff --git a/docs/html/preview/images/opt-in.png b/docs/html/preview/images/opt-in.png
index 0f309c2..7151253 100644
--- a/docs/html/preview/images/opt-in.png
+++ b/docs/html/preview/images/opt-in.png
Binary files differ
diff --git a/docs/html/preview/index.html b/docs/html/preview/index.html
index 4f3f150..4c42d99 100644
--- a/docs/html/preview/index.html
+++ b/docs/html/preview/index.html
@@ -257,7 +257,7 @@
                     Join the community of Android developers testing out the L Developer Preview and
                     share your thoughts and experiences.
                   </p><p class="landing-small">
-                    <a href="https://plus.google.com/communities/113159138894928487684">
+                    <a href="http://g.co/androidldevpreview">
                     Discuss on Google+</a>
                     </p>
                 </div>
diff --git a/docs/html/preview/material/images/list_mail.png b/docs/html/preview/material/images/list_mail.png
index bd107ff..e70291c 100644
--- a/docs/html/preview/material/images/list_mail.png
+++ b/docs/html/preview/material/images/list_mail.png
Binary files differ
diff --git a/docs/html/preview/reference.jd b/docs/html/preview/reference.jd
index f70f7a2..b70e4e5 100644
--- a/docs/html/preview/reference.jd
+++ b/docs/html/preview/reference.jd
@@ -2,12 +2,10 @@
 
 @jd:body
 
-<p>The reference documentation and API difference report are available as downloadable packages.
+<p>The reference documentation and API difference report are available in this downloadable package.
 </p>
 
 <ul>
-  <li><a href="{@docRoot}preview/l-developer-preview-reference.zip">L
+  <li><a href="http://storage.googleapis.com/androiddevelopers/preview/l-developer-preview-reference.zip">L
   Developer Preview reference</a></li>
-  <li><a href="{@docRoot}preview/l-developer-preview-api-diff.zip">L
-  Developer Preview difference report</a></li>
 </ul>
\ No newline at end of file
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 8efc4bc..9d7844b 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -7,7 +7,7 @@
 our issue tracker.</p>
 
 <p>For more support,
-<a href="https://plus.google.com/communities/113159138894928487684">join
+<a href="https://plus.google.com/communities/101985907812750684586">join
 the L Developer Preview Google+ community</a> to discuss your development experiences.
 
 
diff --git a/docs/html/training/wearables/apps/index.jd b/docs/html/training/wearables/apps/index.jd
index 3a4eb70..a0d02fb 100644
--- a/docs/html/training/wearables/apps/index.jd
+++ b/docs/html/training/wearables/apps/index.jd
@@ -59,7 +59,7 @@
       <dd>Learn how to create an Android Studio project that
       contains both the wearable and handheld app modules and how to run the app on a device
       or emulator.</dd>
-    <dt><a href="{@docRoot}training/wearables/apps/activity.html">Creating Custom Layouts</a></dt>
+    <dt><a href="{@docRoot}training/wearables/apps/layouts.html">Creating Custom Layouts</a></dt>
       <dd>Learn how to create and display custom layouts for notifications and
       activities.</dd>
     <dt><a href="{@docRoot}training/wearables/apps/voice.html">Adding Voice Capabilities</a></dt>
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index c9b8ba8..5dd7690 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -152,7 +152,7 @@
                   for a hands-free experience.
                 </p>
                 <p class="landing-small">
-                  <a href="{@docRoot}training/wearables/apps/voice-actions.html">Integrate voice actions</a>
+                  <a href="{@docRoot}training/wearables/apps/voice.html">Integrate voice actions</a>
                 </p>
               </div>
               <div class="col-4">
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 17ce026..72e39bb 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1773,46 +1773,6 @@
     }
 
     /**
-     * Return the glyph Ids for the characters in the string.
-     *
-     * @param text   The text to measure
-     * @param start  The index of the first char to to measure
-     * @param end    The end of the text slice to measure
-     * @param contextStart the index of the first character to use for shaping context,
-     * must be <= start
-     * @param contextEnd the index past the last character to use for shaping context,
-     * must be >= end
-     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
-     * or {@link #DIRECTION_RTL}
-     * @param glyphs array to receive the glyph Ids of the characters.
-     *               Must be at least a large as the text.
-     * @return       the number of glyphs in the returned array
-     *
-     * @hide
-     *
-     * Used only for BiDi / RTL Tests
-     */
-    public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
-            int flags, char[] glyphs) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
-        if ((start | end | contextStart | contextEnd | (end - start)
-                | (start - contextStart) | (contextEnd - end) | (text.length() - end)
-                | (text.length() - contextEnd)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (end - start > glyphs.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
-                flags, glyphs);
-    }
-
-    /**
      * Convenience overload that takes a char array instead of a
      * String.
      *
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 0862cdd..17795f3 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -126,7 +126,34 @@
      */
     public SurfaceTexture(int texName, boolean singleBufferMode) {
         mCreatorLooper = Looper.myLooper();
-        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
+        nativeInit(false, texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
+    }
+
+    /**
+     * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
+     *
+     * In single buffered mode the application is responsible for serializing access to the image
+     * content buffer. Each time the image content is to be updated, the
+     * {@link #releaseTexImage()} method must be called before the image content producer takes
+     * ownership of the buffer. For example, when producing image content with the NDK
+     * ANativeWindow_lock and ANativeWindow_unlockAndPost functions, {@link #releaseTexImage()}
+     * must be called before each ANativeWindow_lock, or that call will fail. When producing
+     * image content with OpenGL ES, {@link #releaseTexImage()} must be called before the first
+     * OpenGL ES function call each frame.
+     *
+     * Unlike {@link #SurfaceTexture(int, boolean)}, which takes an OpenGL texture object name,
+     * this constructor creates the SurfaceTexture in detached mode. A texture name must be passed
+     * in using {@link #attachToGLContext} before calling {@link #releaseTexImage()} and producing
+     * image content using OpenGL ES.
+     *
+     * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
+     *
+     * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
+     * @hide
+     */
+    public SurfaceTexture(boolean singleBufferMode) {
+        mCreatorLooper = Looper.myLooper();
+        nativeInit(true, 0, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
     /**
@@ -339,8 +366,8 @@
         }
     }
 
-    private native void nativeInit(int texName, boolean singleBufferMode,
-            WeakReference<SurfaceTexture> weakSelf)
+    private native void nativeInit(boolean isDetached, int texName,
+            boolean singleBufferMode, WeakReference<SurfaceTexture> weakSelf)
             throws Surface.OutOfResourcesException;
     private native void nativeFinalize();
     private native void nativeGetTransformMatrix(float[] mtx);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index cb48de2..0dc903a 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -117,7 +117,7 @@
         if (sSystemFontMap != null) {
             return create(sSystemFontMap.get(familyName), style);
         }
-        return new Typeface(nativeCreate(familyName, style));
+        return null;
     }
 
     /**
@@ -183,11 +183,9 @@
             if (fontFamily.addFontFromAsset(mgr, path)) {
                 FontFamily[] families = { fontFamily };
                 return createFromFamiliesWithDefault(families);
-            } else {
-                return null;
             }
         }
-        return new Typeface(nativeCreateFromAsset(mgr, path));
+        return null;
     }
 
     /**
@@ -212,11 +210,9 @@
             if (fontFamily.addFont(path)) {
                 FontFamily[] families = { fontFamily };
                 return createFromFamiliesWithDefault(families);
-            } else {
-                return null;
             }
         }
-        return new Typeface(nativeCreateFromFile(path));
+        return null;
     }
 
     /**
@@ -383,12 +379,9 @@
         return result;
     }
 
-    private static native long nativeCreate(String familyName, int style);
     private static native long nativeCreateFromTypeface(long native_instance, int style);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
-    private static native long nativeCreateFromAsset(AssetManager mgr, String path);
-    private static native long nativeCreateFromFile(String path);
     private static native long nativeCreateFromArray(long[] familyArray);
     private static native void nativeSetDefault(long native_instance);
 }
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a704e19..1a96b2f 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -13,6 +13,7 @@
 		font/Font.cpp \
 		AmbientShadow.cpp \
 		Animator.cpp \
+		AnimatorManager.cpp \
 		AssetAtlas.cpp \
 		DamageAccumulator.cpp \
 		FontRenderer.cpp \
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index dc6d852..4a8c122 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -18,6 +18,7 @@
 
 #include "Animator.h"
 
+#include <inttypes.h>
 #include <set>
 
 #include "RenderNode.h"
@@ -35,72 +36,105 @@
         , mDeltaValue(0)
         , mFromValue(0)
         , mInterpolator(0)
-        , mPlayState(NEEDS_START)
+        , mStagingPlayState(NOT_STARTED)
+        , mPlayState(NOT_STARTED)
+        , mHasStartValue(false)
         , mStartTime(0)
-        , mDelayUntil(0)
         , mDuration(300)
         , mStartDelay(0) {
-
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
-    setInterpolator(NULL);
+    delete mInterpolator;
+}
+
+void BaseRenderNodeAnimator::checkMutable() {
+    // Should be impossible to hit as the Java-side also has guards for this
+    LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED,
+            "Animator has already been started!");
 }
 
 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
+    checkMutable();
     delete mInterpolator;
     mInterpolator = interpolator;
 }
 
 void BaseRenderNodeAnimator::setStartValue(float value) {
-    LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
-            "Cannot set the start value after the animator has started!");
-    mFromValue = value;
-    mDeltaValue = (mFinalValue - mFromValue);
-    mPlayState = PENDING;
+    checkMutable();
+    doSetStartValue(value);
 }
 
-void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
-    if (mPlayState == NEEDS_START) {
-        setStartValue(getValue(target));
-    }
+void BaseRenderNodeAnimator::doSetStartValue(float value) {
+    mFromValue = value;
+    mDeltaValue = (mFinalValue - mFromValue);
+    mHasStartValue = true;
 }
 
 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
+    checkMutable();
     mDuration = duration;
 }
 
 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+    checkMutable();
     mStartDelay = startDelay;
 }
 
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
-    if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
-        mDelayUntil = info.frameTimeMs + mStartDelay;
-        return false;
+void BaseRenderNodeAnimator::pushStaging(RenderNode* target, TreeInfo& info) {
+    if (!mHasStartValue) {
+        doSetStartValue(getValue(target));
     }
-
-    if (mDelayUntil > info.frameTimeMs) {
-        return false;
-    }
-
-    if (mPlayState == PENDING) {
-        mPlayState = RUNNING;
-        mStartTime = info.frameTimeMs;
-        // No interpolator was set, use the default
-        if (!mInterpolator) {
-            setInterpolator(Interpolator::createDefaultInterpolator());
+    if (mStagingPlayState > mPlayState) {
+        mPlayState = mStagingPlayState;
+        // Oh boy, we're starting! Man the battle stations!
+        if (mPlayState == RUNNING) {
+            transitionToRunning(info);
         }
     }
+}
+
+void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) {
+    LOG_ALWAYS_FATAL_IF(info.frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", info.frameTimeMs);
+    if (mStartDelay < 0 || mStartDelay > 50000) {
+        ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
+    }
+    mStartTime = info.frameTimeMs + mStartDelay;
+    if (mStartTime < 0) {
+        ALOGW("Ended up with a really weird start time of %" PRId64
+                " with frame time %" PRId64 " and start delay %" PRId64,
+                mStartTime, info.frameTimeMs, mStartDelay);
+        // Set to 0 so that the animate() basically instantly finishes
+        mStartTime = 0;
+    }
+    // No interpolator was set, use the default
+    if (!mInterpolator) {
+        setInterpolator(Interpolator::createDefaultInterpolator());
+    }
+    if (mDuration < 0 || mDuration > 50000) {
+        ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
+    }
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    if (mPlayState < RUNNING) {
+        return false;
+    }
+
+    if (mStartTime > info.frameTimeMs) {
+        info.out.hasAnimations |= true;
+        return false;
+    }
 
     float fraction = 1.0f;
-    if (mPlayState == RUNNING) {
-        fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f;
-        if (fraction >= 1.0f) {
-            fraction = 1.0f;
-            mPlayState = FINISHED;
-        }
+    if (mPlayState == RUNNING && mDuration > 0) {
+        fraction = (float)(info.frameTimeMs - mStartTime) / mDuration;
     }
+    if (fraction >= 1.0f) {
+        fraction = 1.0f;
+        mPlayState = FINISHED;
+    }
+
     fraction = mInterpolator->interpolate(fraction);
     setValue(target, mFromValue + (mDeltaValue * fraction));
 
@@ -108,6 +142,8 @@
         callOnFinishedListener(info);
         return true;
     }
+
+    info.out.hasAnimations |= true;
     return false;
 }
 
@@ -153,7 +189,7 @@
 }
 
 void RenderPropertyAnimator::onAttached(RenderNode* target) {
-    if (mPlayState == NEEDS_START
+    if (!mHasStartValue
             && target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
         setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
     }
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 6cb72c4c..a981b5a 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -50,12 +50,11 @@
     ANDROID_API void setListener(AnimationListener* listener) {
         mListener = listener;
     }
+    ANDROID_API void start() { mStagingPlayState = RUNNING; }
+    ANDROID_API void cancel() { mStagingPlayState = FINISHED; }
 
-    ANDROID_API virtual void onAttached(RenderNode* target) {}
-
-    // Guaranteed to happen before the staging push
-    void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
-
+    virtual void onAttached(RenderNode* target) {}
+    virtual void pushStaging(RenderNode* target, TreeInfo& info);
     bool animate(RenderNode* target, TreeInfo& info);
 
     bool isFinished() { return mPlayState == FINISHED; }
@@ -73,8 +72,7 @@
     void callOnFinishedListener(TreeInfo& info);
 
     enum PlayState {
-        NEEDS_START,
-        PENDING,
+        NOT_STARTED,
         RUNNING,
         FINISHED,
     };
@@ -84,13 +82,19 @@
     float mFromValue;
 
     Interpolator* mInterpolator;
+    PlayState mStagingPlayState;
     PlayState mPlayState;
+    bool mHasStartValue;
     nsecs_t mStartTime;
-    nsecs_t mDelayUntil;
     nsecs_t mDuration;
     nsecs_t mStartDelay;
 
     sp<AnimationListener> mListener;
+
+private:
+    void doSetStartValue(float value);
+    inline void checkMutable();
+    void transitionToRunning(TreeInfo& info);
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
@@ -112,7 +116,7 @@
 
     ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
 
-    ANDROID_API virtual void onAttached(RenderNode* target);
+    virtual void onAttached(RenderNode* target);
 
     ANDROID_API virtual uint32_t dirtyMask();
 
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
new file mode 100644
index 0000000..6a10cf8
--- /dev/null
+++ b/libs/hwui/AnimatorManager.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+#include "AnimatorManager.h"
+
+#include <algorithm>
+
+#include "RenderNode.h"
+
+namespace android {
+namespace uirenderer {
+
+using namespace std;
+
+static void unref(BaseRenderNodeAnimator* animator) {
+    animator->decStrong(0);
+}
+
+AnimatorManager::AnimatorManager(RenderNode& parent)
+        : mParent(parent) {
+}
+
+AnimatorManager::~AnimatorManager() {
+    for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
+    for_each(mAnimators.begin(), mAnimators.end(), unref);
+}
+
+void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+    animator->incStrong(0);
+    animator->onAttached(&mParent);
+    mNewAnimators.push_back(animator.get());
+}
+
+template<typename T>
+static void move_all(T& source, T& dest) {
+    dest.reserve(source.size() + dest.size());
+    for (typename T::iterator it = source.begin(); it != source.end(); it++) {
+        dest.push_back(*it);
+    }
+    source.clear();
+}
+
+void AnimatorManager::pushStaging(TreeInfo& info) {
+    if (mNewAnimators.size()) {
+        // Since this is a straight move, we don't need to inc/dec the ref count
+        move_all(mNewAnimators, mAnimators);
+    }
+    for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
+        (*it)->pushStaging(&mParent, info);
+    }
+}
+
+class AnimateFunctor {
+public:
+    AnimateFunctor(RenderNode& target, TreeInfo& info)
+            : mTarget(target), mInfo(info) {}
+
+    bool operator() (BaseRenderNodeAnimator* animator) {
+        bool remove = animator->animate(&mTarget, mInfo);
+        if (remove) {
+            animator->decStrong(0);
+        }
+        return remove;
+    }
+private:
+    RenderNode& mTarget;
+    TreeInfo& mInfo;
+};
+
+void AnimatorManager::animate(TreeInfo& info) {
+    if (!mAnimators.size()) return;
+
+    // TODO: Can we target this better? For now treat it like any other staging
+    // property push and just damage self before and after animators are run
+
+    mParent.damageSelf(info);
+    info.damageAccumulator->popTransform();
+
+    AnimateFunctor functor(mParent, info);
+    std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
+    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
+    mAnimators.erase(newEnd, mAnimators.end());
+
+    mParent.mProperties.updateMatrix();
+    info.damageAccumulator->pushTransform(&mParent);
+    mParent.damageSelf(info);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
new file mode 100644
index 0000000..2568121
--- /dev/null
+++ b/libs/hwui/AnimatorManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+#ifndef ANIMATORMANAGER_H
+#define ANIMATORMANAGER_H
+
+#include <vector>
+
+#include <cutils/compiler.h>
+#include <utils/StrongPointer.h>
+
+#include "TreeInfo.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+class BaseRenderNodeAnimator;
+class RenderNode;
+
+// Responsible for managing the animators for a single RenderNode
+class AnimatorManager {
+    PREVENT_COPY_AND_ASSIGN(AnimatorManager);
+public:
+    AnimatorManager(RenderNode& parent);
+    ~AnimatorManager();
+
+    void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+
+    void pushStaging(TreeInfo& info);
+    void animate(TreeInfo& info);
+
+private:
+    RenderNode& mParent;
+
+    // To improve the efficiency of resizing & removing from the vector
+    // use manual ref counting instead of sp<>.
+    std::vector<BaseRenderNodeAnimator*> mNewAnimators;
+    std::vector<BaseRenderNodeAnimator*> mAnimators;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* ANIMATORMANAGER_H */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 8e99b9a..02b0372 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -58,7 +58,7 @@
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
 
-bool DeferredLayerUpdater::apply(TreeInfo& info) {
+bool DeferredLayerUpdater::apply() {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index c76bd5e..5905b95 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -75,7 +75,7 @@
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply(TreeInfo& info);
+    ANDROID_API bool apply();
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 131384a..e803ec3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -62,7 +62,7 @@
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0)
-        , mNeedsAnimatorsSync(false)
+        , mAnimatorManager(*this)
         , mLayer(0) {
 }
 
@@ -117,6 +117,10 @@
     prepareTreeImpl(info);
 }
 
+void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+    mAnimatorManager.addAnimator(animator);
+}
+
 void RenderNode::damageSelf(TreeInfo& info) {
     if (isRenderable()) {
         if (properties().getClipDamageToBounds()) {
@@ -193,11 +197,11 @@
     info.damageAccumulator->pushTransform(this);
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingPropertiesChanges(info);
-        evaluateAnimations(info);
+        mAnimatorManager.animate(info);
     } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
         pushStagingPropertiesChanges(info);
     } else if (info.mode == TreeInfo::MODE_RT_ONLY) {
-        evaluateAnimations(info);
+        mAnimatorManager.animate(info);
     }
 
     prepareLayer(info);
@@ -210,33 +214,11 @@
     info.damageAccumulator->popTransform();
 }
 
-class PushAnimatorsFunctor {
-public:
-    PushAnimatorsFunctor(RenderNode* target, TreeInfo& info)
-            : mTarget(target), mInfo(info) {}
-
-    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
-        animator->setupStartValueIfNecessary(mTarget, mInfo);
-        return animator->isFinished();
-    }
-private:
-    RenderNode* mTarget;
-    TreeInfo& mInfo;
-};
-
 void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
     // Push the animators first so that setupStartValueIfNecessary() is called
     // before properties() is trampled by stagingProperties(), as they are
     // required by some animators.
-    if (mNeedsAnimatorsSync) {
-        mAnimators.resize(mStagingAnimators.size());
-        std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
-        PushAnimatorsFunctor functor(this, info);
-        // hint: this means copy_if_not()
-        it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
-                mAnimators.begin(), functor);
-        mAnimators.resize(std::distance(mAnimators.begin(), it));
-    }
+    mAnimatorManager.pushStaging(info);
     if (mDirtyPropertyFields) {
         mDirtyPropertyFields = 0;
         damageSelf(info);
@@ -267,8 +249,7 @@
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
         // that are no longer used
-        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info.renderState);
-        oldTreeInfo.damageAccumulator = info.damageAccumulator;
+        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info);
         prepareSubTree(oldTreeInfo, mDisplayListData);
         delete mDisplayListData;
         mDisplayListData = mStagingDisplayListData;
@@ -277,39 +258,6 @@
     }
 }
 
-class AnimateFunctor {
-public:
-    AnimateFunctor(RenderNode* target, TreeInfo& info)
-            : mTarget(target), mInfo(info) {}
-
-    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
-        return animator->animate(mTarget, mInfo);
-    }
-private:
-    RenderNode* mTarget;
-    TreeInfo& mInfo;
-};
-
-void RenderNode::evaluateAnimations(TreeInfo& info) {
-    if (!mAnimators.size()) return;
-
-    // TODO: Can we target this better? For now treat it like any other staging
-    // property push and just damage self before and after animators are run
-
-    damageSelf(info);
-    info.damageAccumulator->popTransform();
-
-    AnimateFunctor functor(this, info);
-    std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
-    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
-    mAnimators.erase(newEnd, mAnimators.end());
-    mProperties.updateMatrix();
-    info.out.hasAnimations |= mAnimators.size();
-
-    info.damageAccumulator->pushTransform(this);
-    damageSelf(info);
-}
-
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 3980dad..7d42b59 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -20,18 +20,11 @@
     #define LOG_TAG "OpenGLRenderer"
 #endif
 
-#include <set>
-#include <vector>
-
 #include <SkCamera.h>
 #include <SkMatrix.h>
 
-#include <private/hwui/DrawGlInfo.h>
-
-#include <utils/KeyedVector.h>
 #include <utils/LinearAllocator.h>
 #include <utils/RefBase.h>
-#include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
@@ -39,6 +32,7 @@
 
 #include <androidfw/ResourceTypes.h>
 
+#include "AnimatorManager.h"
 #include "DamageAccumulator.h"
 #include "Debug.h"
 #include "Matrix.h"
@@ -176,19 +170,7 @@
     ANDROID_API virtual void prepareTree(TreeInfo& info);
 
     // UI thread only!
-    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-        animator->onAttached(this);
-        mStagingAnimators.insert(animator);
-        mNeedsAnimatorsSync = true;
-    }
-
-    // UI thread only!
-    ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-        mStagingAnimators.erase(animator);
-        // Force a sync of the staging property value
-        mDirtyPropertyFields |= animator->dirtyMask();
-        mNeedsAnimatorsSync = true;
-    }
+    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
 
 protected:
     virtual void damageSelf(TreeInfo& info);
@@ -262,7 +244,6 @@
     void prepareTreeImpl(TreeInfo& info);
     void pushStagingPropertiesChanges(TreeInfo& info);
     void pushStagingDisplayListChanges(TreeInfo& info);
-    void evaluateAnimations(TreeInfo& info);
     void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
     void applyLayerPropertiesToLayer(TreeInfo& info);
     void prepareLayer(TreeInfo& info);
@@ -278,9 +259,8 @@
     DisplayListData* mDisplayListData;
     DisplayListData* mStagingDisplayListData;
 
-    bool mNeedsAnimatorsSync;
-    std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
-    std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+    friend class AnimatorManager;
+    AnimatorManager mAnimatorManager;
 
     // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
     // being in ~RenderNode() which may happen on any thread.
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 249e525..083100e 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -79,6 +79,17 @@
         , errorHandler(NULL)
     {}
 
+    explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
+        : mode(mode)
+        , frameTimeMs(clone.frameTimeMs)
+        , animationHook(clone.animationHook)
+        , prepareTextures(mode == MODE_FULL)
+        , damageAccumulator(clone.damageAccumulator)
+        , renderState(clone.renderState)
+        , renderer(clone.renderer)
+        , errorHandler(clone.errorHandler)
+    {}
+
     const TraversalMode mode;
     nsecs_t frameTimeMs;
     AnimationHook* animationHook;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 281a8e1..9c3cf44 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -123,8 +123,8 @@
     mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
 }
 
-void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
-    bool success = layerUpdater->apply(info);
+void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
+    bool success = layerUpdater->apply();
     LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
     if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
         mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
@@ -237,8 +237,7 @@
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
-    layer->apply(info);
+    layer->apply();
     return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d2ce1a6..dbfb3d2 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -56,7 +56,7 @@
     void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
-    void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
+    void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
     void prepareTree(TreeInfo& info);
     void draw();
     void destroyCanvasAndSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index fddffd5..dd34e09 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -127,7 +127,7 @@
     Caches::getInstance().textureCache.resetMarkInUse();
 
     for (size_t i = 0; i < mLayers.size(); i++) {
-        mContext->processLayerUpdate(mLayers[i].get(), info);
+        mContext->processLayerUpdate(mLayers[i].get());
     }
     mLayers.clear();
     mContext->prepareTree(info);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 2831d9e..a913e59c 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -33,6 +33,7 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 
@@ -339,6 +340,11 @@
     public void setVisibility(int visibility) {
         super.setVisibility(visibility);
         mSurfaceView.setVisibility(visibility);
+        if (visibility == View.VISIBLE) {
+            createSessionOverlayView();
+        } else {
+            removeSessionOverlayView();
+        }
     }
 
     private void release() {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 41b1f75..186b570 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -81,6 +81,8 @@
     private long mScreenOffTime;
     private int mShowing;
 
+    private long mBucketDroppedNegativeTimeMs;
+
     private boolean mSaver;
     private int mSaverTriggerLevel;
     private boolean mWarning;
@@ -108,6 +110,11 @@
     @Override
     public void update(int batteryLevel, int bucket, long screenOffTime) {
         mBatteryLevel = batteryLevel;
+        if (bucket >= 0) {
+            mBucketDroppedNegativeTimeMs = 0;
+        } else if (bucket < mBucket) {
+            mBucketDroppedNegativeTimeMs = System.currentTimeMillis();
+        }
         mBucket = bucket;
         mScreenOffTime = screenOffTime;
         mFallbackDialogs.update(batteryLevel, bucket, screenOffTime);
@@ -146,6 +153,7 @@
     private void showInvalidChargerNotification() {
         final Notification.Builder nb = new Notification.Builder(mContext)
                 .setSmallIcon(R.drawable.ic_power_low)
+                .setWhen(0)
                 .setShowWhen(false)
                 .setOngoing(true)
                 .setContentTitle(mContext.getString(R.string.invalid_charger_title))
@@ -166,6 +174,8 @@
                 : R.string.battery_low_percent_format;
         final Notification.Builder nb = new Notification.Builder(mContext)
                 .setSmallIcon(R.drawable.ic_power_low)
+                // Bump the notification when the bucket dropped.
+                .setWhen(mBucketDroppedNegativeTimeMs)
                 .setShowWhen(false)
                 .setContentTitle(mContext.getString(R.string.battery_low_title))
                 .setContentText(mContext.getString(textRes, mBatteryLevel))
@@ -198,6 +208,7 @@
                 .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
                 .setContentText(mContext.getString(R.string.battery_saver_notification_text))
                 .setOngoing(true)
+                .setWhen(0)
                 .setShowWhen(false)
                 .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2f5524e..19fff55 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -45,7 +45,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.bluetooth.BluetoothTetheringDataTracker;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -410,7 +409,8 @@
 
     /**
      * used to remove a network request, either a listener or a real request
-     * includes a NetworkRequest
+     * arg1 = UID of caller
+     * obj  = NetworkRequest
      */
     private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
 
@@ -911,8 +911,6 @@
             switch (config.radio) {
                 case TYPE_DUMMY:
                     return new DummyDataStateTracker(targetNetworkType, config.name);
-                case TYPE_BLUETOOTH:
-                    return BluetoothTetheringDataTracker.getInstance();
                 case TYPE_WIMAX:
                     return makeWimaxStateTracker(mContext, mTrackerHandler);
                 case TYPE_PROXY:
@@ -3336,10 +3334,15 @@
         }
     }
 
-    private void handleReleaseNetworkRequest(NetworkRequest request) {
-        if (DBG) log("releasing NetworkRequest " + request);
-        NetworkRequestInfo nri = mNetworkRequests.remove(request);
+    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
+        NetworkRequestInfo nri = mNetworkRequests.get(request);
         if (nri != null) {
+            if (nri.mUid != callingUid) {
+                if (DBG) log("Attempt to release unowned NetworkRequest " + request);
+                return;
+            }
+            if (DBG) log("releasing NetworkRequest " + request);
+            mNetworkRequests.remove(request);
             // tell the network currently servicing this that it's no longer interested
             NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (affectedNetwork != null) {
@@ -3485,7 +3488,7 @@
                     break;
                 }
                 case EVENT_RELEASE_NETWORK_REQUEST: {
-                    handleReleaseNetworkRequest((NetworkRequest) msg.obj);
+                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
                     break;
                 }
             }
@@ -5463,8 +5466,8 @@
 
     @Override
     public void releaseNetworkRequest(NetworkRequest networkRequest) {
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST,
-                networkRequest));
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(),
+                0, networkRequest));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 512ebc6..1b71518 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -23,6 +23,7 @@
 import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
 import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.net.ScoredNetwork;
 import android.os.RemoteException;
 import android.text.TextUtils;
@@ -165,12 +166,12 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
-        String currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
+        NetworkScorerAppData currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
         if (currentScorer == null) {
             writer.println("Scoring is disabled.");
             return;
         }
-        writer.println("Current scorer: " + currentScorer);
+        writer.println("Current scorer: " + currentScorer.mPackageName);
         writer.flush();
 
         for (INetworkScoreCache scoreCache : getScoreCaches()) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0825f2e..f4e9876 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -79,8 +79,6 @@
     private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
     private static final String ATTR_RESOLVEDTYPE = "resolved_type";
     private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
-    private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
-    private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
     private static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
 
     final ActivityManagerService service; // owner
@@ -1064,20 +1062,10 @@
         }
         out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
         out.attribute(null, ATTR_USERID, String.valueOf(userId));
+
         if (taskDescription != null) {
-            final String label = taskDescription.getLabel();
-            if (label != null) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
-            }
-            final int colorPrimary = taskDescription.getPrimaryColor();
-            if (colorPrimary != 0) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
-            }
-            final Bitmap icon = taskDescription.getIcon();
-            if (icon != null) {
-                TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX +
-                        createTime);
-            }
+            TaskPersister.saveTaskDescription(taskDescription, String.valueOf(task.taskId) +
+                    ACTIVITY_ICON_SUFFIX + createTime, out);
         }
 
         out.startTag(null, TAG_INTENT);
@@ -1100,10 +1088,9 @@
         String resolvedType = null;
         boolean componentSpecified = false;
         int userId = 0;
-        String activityLabel = null;
-        int activityColor = 0;
         long createTime = -1;
         final int outerDepth = in.getDepth();
+        TaskDescription taskDescription = new TaskDescription();
 
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
@@ -1122,10 +1109,9 @@
                 componentSpecified = Boolean.valueOf(attrValue);
             } else if (ATTR_USERID.equals(attrName)) {
                 userId = Integer.valueOf(attrValue);
-            } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
-                activityLabel = attrValue;
-            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
-                activityColor = (int) Long.parseLong(attrValue, 16);
+            } else if (TaskPersister.readTaskDescriptionAttribute(taskDescription, attrName,
+                    attrValue)) {
+                // Completed in TaskPersister.readTaskDescriptionAttribute()
             } else {
                 Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
             }
@@ -1169,12 +1155,11 @@
 
         r.persistentState = persistentState;
 
-        Bitmap icon = null;
         if (createTime >= 0) {
-            icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX +
-                    createTime);
+            taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) +
+                    ACTIVITY_ICON_SUFFIX + createTime));
         }
-        r.taskDescription = new TaskDescription(activityLabel, icon, activityColor);
+        r.taskDescription = taskDescription;
         r.createTime = createTime;
 
         return r;
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index c79b33d..132b244 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -56,6 +57,9 @@
 
     private static final String TAG_TASK = "task";
 
+    private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
+    private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
+
     private static File sImagesDir;
     private static File sTasksDir;
 
@@ -143,6 +147,36 @@
         }
     }
 
+    static void saveTaskDescription(ActivityManager.TaskDescription taskDescription,
+            String iconFilename, XmlSerializer out) throws IOException {
+        if (taskDescription != null) {
+            final String label = taskDescription.getLabel();
+            if (label != null) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
+            }
+            final int colorPrimary = taskDescription.getPrimaryColor();
+            if (colorPrimary != 0) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
+            }
+            final Bitmap icon = taskDescription.getIcon();
+            if (icon != null) {
+                saveImage(icon, iconFilename);
+            }
+        }
+    }
+
+    static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription,
+        String attrName, String attrValue) {
+        if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
+            taskDescription.setLabel(attrValue);
+            return true;
+        } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
+            taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16));
+            return true;
+        }
+        return false;
+    }
+
     ArrayList<TaskRecord> restoreTasksLocked() {
         final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 57dee2e..0bd7ef9 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -60,6 +60,7 @@
     private static final String ATTR_LASTDESCRIPTION = "last_description";
     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
     private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
+    private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_";
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
@@ -138,7 +139,8 @@
             String _affinity, ComponentName _realActivity, ComponentName _origActivity,
             boolean _rootWasReset, boolean _askedCompatMode, int _taskType, int _userId,
             String _lastDescription, ArrayList<ActivityRecord> activities, long _lastActiveTime,
-            long lastTimeMoved, boolean neverRelinquishIdentity) {
+            long lastTimeMoved, boolean neverRelinquishIdentity,
+            ActivityManager.TaskDescription _lastTaskDescription) {
         mService = service;
         taskId = _taskId;
         intent = _intent;
@@ -158,8 +160,7 @@
         mActivities = activities;
         mLastTimeMoved = lastTimeMoved;
         mNeverRelinquishIdentity = neverRelinquishIdentity;
-        // Recompute the task description for this task
-        updateTaskDescription();
+        lastTaskDescription = _lastTaskDescription;
     }
 
     void touchActiveTime() {
@@ -714,6 +715,11 @@
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
         }
 
+        if (lastTaskDescription != null) {
+            TaskPersister.saveTaskDescription(lastTaskDescription, String.valueOf(taskId) +
+                    LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out);
+        }
+
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
             affinityIntent.saveToXml(out);
@@ -758,11 +764,12 @@
         int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
         int userId = 0;
         String lastDescription = null;
-        long lastActiveTime = 0;
+        long lastActiveTime = -1;
         long lastTimeOnTop = 0;
         boolean neverRelinquishIdentity = true;
         int taskId = -1;
         final int outerDepth = in.getDepth();
+        ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription();
 
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
@@ -793,6 +800,9 @@
                 lastTimeOnTop = Long.valueOf(attrValue);
             } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
                 neverRelinquishIdentity = Boolean.valueOf(attrValue);
+            } else if (TaskPersister.readTaskDescriptionAttribute(taskDescription, attrName,
+                    attrValue)) {
+                // Completed in TaskPersister.readTaskDescriptionAttribute()
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
             }
@@ -824,10 +834,15 @@
             }
         }
 
+        if (lastActiveTime >= 0) {
+            taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) +
+                    LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime));
+        }
+
         final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
                 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
                 askedCompatMode, taskType, userId, lastDescription, activities, lastActiveTime,
-                lastTimeOnTop, neverRelinquishIdentity);
+                lastTimeOnTop, neverRelinquishIdentity, taskDescription);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             final ActivityRecord r = activities.get(activityNdx);
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 74eaf2a..8de6763 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -27,18 +27,18 @@
 /**
  * Handles CEC command &lt;Active Source&gt;.
  * <p>
- * Used by feature actions that need to handle the command in their flow.
+ * Used by feature actions that need to handle the command in their flow. Only for TV
+ * local device.
  */
 final class ActiveSourceHandler {
     private static final String TAG = "ActiveSourceHandler";
 
-    private final HdmiCecLocalDevice mSource;
+    private final HdmiCecLocalDeviceTv mSource;
     private final HdmiControlService mService;
     @Nullable
     private final IHdmiControlCallback mCallback;
 
-    static ActiveSourceHandler create(HdmiCecLocalDevice source,
-            IHdmiControlCallback callback) {
+    static ActiveSourceHandler create(HdmiCecLocalDeviceTv source, IHdmiControlCallback callback) {
         if (source == null) {
             Slog.e(TAG, "Wrong arguments");
             return null;
@@ -46,7 +46,7 @@
         return new ActiveSourceHandler(source, callback);
     }
 
-    private ActiveSourceHandler(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
+    private ActiveSourceHandler(HdmiCecLocalDeviceTv source, IHdmiControlCallback callback) {
         mSource = source;
         mService = mSource.getService();
         mCallback = callback;
@@ -55,48 +55,46 @@
     /**
      * Handles the incoming active source command.
      *
-     * @param deviceLogicalAddress logical address of the device to be the active source
-     * @param routingPath routing path of the device to be the active source
+     * @param activeAddress logical address of the device to be the active source
+     * @param activePath routing path of the device to be the active source
      */
-    void process(int deviceLogicalAddress, int routingPath) {
-        if (getSourcePath() == routingPath && mSource.getActiveSource() == getSourceAddress()) {
+    void process(int activeAddress, int activePath) {
+        // Seq #17
+        HdmiCecLocalDeviceTv tv = mSource;
+        if (getSourcePath() == activePath && tv.getActiveSource() == getSourceAddress()) {
             invokeCallback(HdmiCec.RESULT_SUCCESS);
             return;
         }
-        HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress);
+        HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress);
         if (device == null) {
             // "New device action" initiated by <Active Source> does not require
             // "Routing change action".
-            mSource.addAndStartAction(new NewDeviceAction(mSource, deviceLogicalAddress,
-                    routingPath, false));
+            tv.addAndStartAction(new NewDeviceAction(tv, activeAddress, activePath, false));
         }
 
-        if (!mSource.isInPresetInstallationMode()) {
-            int prevActiveInput = mSource.getActivePortId();
-            mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
-            if (prevActiveInput != mSource.getActivePortId()) {
-                // TODO: change port input here.
+        int currentActive = tv.getActiveSource();
+        int currentPath = tv.getActivePath();
+        if (!tv.isInPresetInstallationMode()) {
+            tv.updateActiveSource(activeAddress, activePath);
+            if (currentActive != activeAddress && currentPath != activePath) {
+                tv.updateActivePortId(mService.pathToPortId(activePath));
             }
             invokeCallback(HdmiCec.RESULT_SUCCESS);
         } else {
             // TV is in a mode that should keep its current source/input from
             // being changed for its operation. Reclaim the active source
             // or switch the port back to the one used for the current mode.
-            if (mSource.getActiveSource() == getSourceAddress()) {
+            if (currentActive == getSourceAddress()) {
                 HdmiCecMessage activeSource =
-                        HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
-                                getSourcePath());
+                        HdmiCecMessageBuilder.buildActiveSource(currentActive, currentPath);
                 mService.sendCecCommand(activeSource);
-                mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
+                tv.updateActiveSource(currentActive, currentPath);
                 invokeCallback(HdmiCec.RESULT_SUCCESS);
             } else {
-                int activePath = mSource.getActivePath();
-                mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
-                        routingPath, activePath));
-                // TODO: Start port select action here
-                // PortSelectAction action = new PortSelectAction(mService, getSourceAddress(),
-                // activePath, mCallback);
-                // mService.addActionAndStart(action);
+                HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(
+                        getSourceAddress(), activePath, currentPath);
+                mService.sendCecCommand(routingChange);
+                tv.addAndStartAction(new RoutingControlAction(tv, currentPath, mCallback));
             }
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index dbe3b80..b97350d 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -77,7 +77,7 @@
      * @param target target logical device that will be a new active source
      * @param callback callback object
      */
-    public DeviceSelectAction(HdmiCecLocalDevice source,
+    public DeviceSelectAction(HdmiCecLocalDeviceTv source,
             HdmiCecDeviceInfo target, IHdmiControlCallback callback) {
         super(source);
         mCallback = callback;
@@ -116,7 +116,7 @@
                 if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) {
                     int activePath = HdmiUtils.twoBytesToInt(params);
                     ActiveSourceHandler
-                            .create(localDevice(), mCallback)
+                            .create((HdmiCecLocalDeviceTv) localDevice(), mCallback)
                             .process(cmd.getSource(), activePath);
                     finish();
                     return true;
@@ -164,8 +164,10 @@
     }
 
     private void turnOnDevice() {
-        sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER);
-        sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION);
+        sendUserControlPressedAndReleased(mTarget.getLogicalAddress(),
+                HdmiConstants.UI_COMMAND_POWER);
+        sendUserControlPressedAndReleased(mTarget.getLogicalAddress(),
+                HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION);
         mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
         addTimer(mState, TIMEOUT_POWER_ON_MS);
     }
@@ -177,13 +179,6 @@
         addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS);
     }
 
-    private void sendRemoteKeyCommand(int keyCode) {
-        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
-                mTarget.getLogicalAddress(), keyCode));
-        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
-                mTarget.getLogicalAddress()));
-    }
-
     @Override
     public void handleTimerEvent(int timeoutState) {
         if (mState != timeoutState) {
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index 0ec17f6..cf28f05 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -248,4 +248,11 @@
     protected final int getSourcePath() {
         return mSource.getDeviceInfo().getPhysicalAddress();
     }
+
+    protected void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) {
+        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
+                getSourceAddress(), targetAddress, uiCommand));
+        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+                getSourceAddress(), targetAddress));
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 6f7f5c2..bf7e57b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -125,6 +125,12 @@
             return true;
         }
         switch (message.getOpcode()) {
+            case HdmiCec.MESSAGE_ACTIVE_SOURCE:
+                return handleActiveSource(message);
+            case HdmiCec.MESSAGE_INACTIVE_SOURCE:
+                return handleInactiveSource(message);
+            case HdmiCec.MESSAGE_REQUEST_ACTIVE_SOURCE:
+                return handleRequestActiveSource(message);
             case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
                 return handleGetMenuLanguage(message);
             case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
@@ -145,6 +151,8 @@
                 return handleSetSystemAudioMode(message);
             case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
                 return handleSystemAudioModeStatus(message);
+            case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
+                return handleReportAudioStatus(message);
             default:
                 return false;
         }
@@ -193,6 +201,21 @@
     }
 
     @ServiceThreadOnly
+    protected boolean handleActiveSource(HdmiCecMessage message) {
+        return false;
+    }
+
+    @ServiceThreadOnly
+    protected boolean handleInactiveSource(HdmiCecMessage message) {
+        return false;
+    }
+
+    @ServiceThreadOnly
+    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
+        return false;
+    }
+
+    @ServiceThreadOnly
     protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
         Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
@@ -242,6 +265,10 @@
         return false;
     }
 
+    protected boolean handleReportAudioStatus(HdmiCecMessage message) {
+        return false;
+    }
+
     @ServiceThreadOnly
     final void handleAddressAllocated(int logicalAddress) {
         assertRunOnServiceThread();
@@ -383,15 +410,24 @@
         }
     }
 
-    /**
-     * Returns the active routing path.
-     */
+    void setActiveSource(int source) {
+        synchronized (mLock) {
+            mActiveSource = source;
+        }
+    }
+
     int getActivePath() {
         synchronized (mLock) {
             return mActiveRoutingPath;
         }
     }
 
+    void setActivePath(int path) {
+        synchronized (mLock) {
+            mActiveRoutingPath = path;
+        }
+    }
+
     /**
      * Returns the ID of the active HDMI port. The active port is the one that has the active
      * routing path connected to it directly or indirectly under the device hierarchy.
@@ -429,6 +465,13 @@
     }
 
     boolean isInPresetInstallationMode() {
+        // TODO: Change this to check the right flag.
+        synchronized (mLock) {
+            return !mInputChangeEnabled;
+        }
+    }
+
+    boolean isHdmiControlEnabled() {
         synchronized (mLock) {
             return !mInputChangeEnabled;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 0333dbf..718072a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -48,6 +48,20 @@
     @GuardedBy("mLock")
     private boolean mSystemAudioMode;
 
+    // The previous port id (input) before switching to the new one. This is remembered in order to
+    // be able to switch to it upon receiving <Inactive Source> from currently active source.
+    // This remains valid only when the active source was switched via one touch play operation
+    // (either by TV or source device). Manual port switching invalidates this value to
+    // HdmiConstants.PORT_INVALID, for which case <Inactive Source> does not do anything.
+    @GuardedBy("mLock")
+    private int mPrevPortId;
+
+    @GuardedBy("mLock")
+    private int mSystemAudioVolume = HdmiConstants.UNKNOWN_VOLUME;
+
+    @GuardedBy("mLock")
+    private boolean mSystemAudioMute = false;
+
     // Copy of mDeviceInfos to guarantee thread-safety.
     @GuardedBy("mLock")
     private List<HdmiCecDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
@@ -62,7 +76,7 @@
 
     HdmiCecLocalDeviceTv(HdmiControlService service) {
         super(service, HdmiCec.DEVICE_TV);
-
+        mPrevPortId = HdmiConstants.INVALID_PORT_ID;
         // TODO: load system audio mode and set it to mSystemAudioMode.
     }
 
@@ -90,6 +104,10 @@
     @ServiceThreadOnly
     void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
+        if (targetAddress == HdmiCec.ADDR_INTERNAL) {
+            handleSelectInternalSource(callback);
+            return;
+        }
         HdmiCecDeviceInfo targetDevice = getDeviceInfo(targetAddress);
         if (targetDevice == null) {
             invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE);
@@ -99,30 +117,85 @@
         addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
     }
 
-    /**
-     * Performs the action routing control.
-     *
-     * @param portId new HDMI port to route to
-     * @param callback callback object to report the result with
-     */
     @ServiceThreadOnly
-    void portSelect(int portId, IHdmiControlCallback callback) {
+    private void handleSelectInternalSource(IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        if (isInPresetInstallationMode()) {
+        // Seq #18
+        if (isHdmiControlEnabled() && getActiveSource() != mAddress) {
+            updateActiveSource(mAddress, mService.getPhysicalAddress());
+            // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
+            HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+                    mAddress, mService.getPhysicalAddress());
+            mService.sendCecCommand(activeSource);
+        }
+    }
+
+    @ServiceThreadOnly
+    void updateActiveSource(int activeSource, int activePath) {
+        assertRunOnServiceThread();
+        // Seq #14
+        if (activeSource == getActiveSource() && activePath == getActivePath()) {
+            return;
+        }
+        setActiveSource(activeSource);
+        setActivePath(activePath);
+        if (getDeviceInfo(activeSource) != null && activeSource != mAddress) {
+            if (mService.pathToPortId(activePath) == getActivePortId()) {
+                setPrevPortId(getActivePortId());
+            }
+            // TODO: Show the OSD banner related to the new active source device.
+        } else {
+            // TODO: If displayed, remove the OSD banner related to the previous
+            //       active source device.
+        }
+    }
+
+    /**
+     * Returns the previous port id kept to handle input switching on <Inactive Source>.
+     */
+    int getPrevPortId() {
+        synchronized (mLock) {
+            return mPrevPortId;
+        }
+    }
+
+    /**
+     * Sets the previous port id. INVALID_PORT_ID invalidates it, hence no actions will be
+     * taken for <Inactive Source>.
+     */
+    void setPrevPortId(int portId) {
+        synchronized (mLock) {
+            mPrevPortId = portId;
+        }
+    }
+
+    @ServiceThreadOnly
+    void updateActivePortId(int portId) {
+        assertRunOnServiceThread();
+        // Seq #15
+        if (portId == getActivePortId()) {
+            return;
+        }
+        setPrevPortId(portId);
+        // TODO: Actually switch the physical port here. Handle PAP/PIP as well.
+        //       Show OSD port change banner
+    }
+
+    @ServiceThreadOnly
+    void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        // Seq #20
+        if (!isHdmiControlEnabled() || portId == getActivePortId()) {
             invokeCallback(callback, HdmiCec.RESULT_INCORRECT_MODE);
             return;
         }
-        // Make sure this call does not stem from <Active Source> message reception, in
-        // which case the two ports will be the same.
-        if (portId == getActivePortId()) {
-            invokeCallback(callback, HdmiCec.RESULT_SUCCESS);
-            return;
-        }
-        setActivePortId(portId);
+        // TODO: Make sure this call does not stem from <Active Source> message reception.
 
+        setActivePortId(portId);
         // TODO: Return immediately if the operation is triggered by <Text/Image View On>
+        //       and this is the first notification about the active input after power-on.
         // TODO: Handle invalid port id / active input which should be treated as an
-        //        internal tuner.
+        //       internal tuner.
 
         removeAction(RoutingControlAction.class);
 
@@ -168,6 +241,61 @@
 
     @Override
     @ServiceThreadOnly
+    protected boolean handleActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int activePath = HdmiUtils.twoBytesToInt(message.getParams());
+        ActiveSourceHandler.create(this, null).process(message.getSource(), activePath);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleInactiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // Seq #10
+
+        // Ignore <Inactive Source> from non-active source device.
+        if (getActiveSource() != message.getSource()) {
+            return true;
+        }
+        if (isInPresetInstallationMode()) {
+            return true;
+        }
+        int portId = getPrevPortId();
+        if (portId != HdmiConstants.INVALID_PORT_ID) {
+            // TODO: Do this only if TV is not showing multiview like PIP/PAP.
+
+            HdmiCecDeviceInfo inactiveSource = getDeviceInfo(message.getSource());
+            if (inactiveSource == null) {
+                return true;
+            }
+            if (mService.pathToPortId(inactiveSource.getPhysicalAddress()) == portId) {
+                return true;
+            }
+            // TODO: Switch the TV freeze mode off
+
+            setActivePortId(portId);
+            doManualPortSwitching(portId, null);
+            setPrevPortId(HdmiConstants.INVALID_PORT_ID);
+        }
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // Seq #19
+        int address = getDeviceInfo().getLogicalAddress();
+        if (address == getActiveSource()) {
+            mService.sendCecCommand(
+                    HdmiCecMessageBuilder.buildActiveSource(address, getActivePath()));
+        }
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
     protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
         HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
@@ -231,6 +359,22 @@
         return true;
     }
 
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleReportAudioStatus(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        byte params[] = message.getParams();
+        if (params.length < 1) {
+            Slog.w(TAG, "Invalide <Report Audio Status> message:" + message);
+            return true;
+        }
+        int mute = params[0] & 0x80;
+        int volume = params[0] & 0x7F;
+        setAudioStatus(mute == 0x80, volume);
+        return true;
+    }
+
     @ServiceThreadOnly
     private void launchDeviceDiscovery() {
         assertRunOnServiceThread();
@@ -336,9 +480,64 @@
         }
     }
 
-    @ServiceThreadOnly
     void setAudioStatus(boolean mute, int volume) {
-        mService.setAudioStatus(mute, volume);
+        synchronized (mLock) {
+            mSystemAudioMute = mute;
+            mSystemAudioVolume = volume;
+            // TODO: pass volume to service (audio service) after scale it to local volume level.
+            mService.setAudioStatus(mute, volume);
+        }
+    }
+
+    @ServiceThreadOnly
+    void changeVolume(int curVolume, int delta, int maxVolume) {
+        assertRunOnServiceThread();
+        if (delta == 0 || !isSystemAudioOn()) {
+            return;
+        }
+
+        int targetVolume = curVolume + delta;
+        int cecVolume = VolumeControlAction.scaleToCecVolume(targetVolume, maxVolume);
+        synchronized (mLock) {
+            // If new volume is the same as current system audio volume, just ignore it.
+            // Note that UNKNOWN_VOLUME is not in range of cec volume scale.
+            if (cecVolume == mSystemAudioVolume) {
+                // Update tv volume with system volume value.
+                mService.setAudioStatus(false,
+                        VolumeControlAction.scaleToCustomVolume(mSystemAudioVolume, maxVolume));
+                return;
+            }
+        }
+
+        // Remove existing volume action.
+        removeAction(VolumeControlAction.class);
+
+        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        addAndStartAction(VolumeControlAction.ofVolumeChange(this, avr.getLogicalAddress(),
+                cecVolume, delta > 0));
+    }
+
+    @ServiceThreadOnly
+    void changeMute(boolean mute) {
+        assertRunOnServiceThread();
+        if (!isSystemAudioOn()) {
+            return;
+        }
+
+        // Remove existing volume action.
+        removeAction(VolumeControlAction.class);
+        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        addAndStartAction(VolumeControlAction.ofMute(this, avr.getLogicalAddress(), mute));
+    }
+
+    private boolean isSystemAudioOn() {
+        if (getAvrDeviceInfo() == null) {
+            return false;
+        }
+
+        synchronized (mLock) {
+            return mSystemAudioMode;
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index 5294506..ab5b8d8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -97,5 +97,12 @@
 
     static final int UNKNOWN_VOLUME = -1;
 
+    // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
+    // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
+    // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
+    // TODO: This value might need tweaking per product basis. Consider putting it
+    //       in config.xml to allow customization.
+    static final int IRT_MS = 300;
+
     private HdmiConstants() { /* cannot be instantiated */ }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 53cb81d..ad95181 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -582,7 +582,7 @@
                         invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
                         return;
                     }
-                    tv.portSelect(portId, callback);
+                    tv.doManualPortSwitching(portId, callback);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index c3078a2..5d81251 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.hdmi;
 
+import static com.android.server.hdmi.HdmiConstants.IRT_MS;
+
 import android.hardware.hdmi.HdmiCecMessage;
 import android.util.Slog;
 import android.view.KeyEvent;
@@ -38,13 +40,6 @@
     // persists throughout the process till it is set back to {@code STATE_NONE} at the end.
     private static final int STATE_PROCESSING_KEYCODE = 1;
 
-    // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
-    // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
-    // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
-    // TODO: This value might need tweaking per product basis. Consider putting it
-    //       in config.xml to allow customization.
-    private static final int IRT_MS = 450;
-
     // Logical address of the device to which the UCP/UCP commands are sent.
     private final int mTargetAddress;
 
@@ -77,7 +72,6 @@
      *
      * @param keyCode key code of {@link KeyEvent} object
      * @param isPressed true if the key event is of {@link KeyEvent#ACTION_DOWN}
-     * @param param additional parameter that comes with the key event
      */
     void processKeyEvent(int keyCode, boolean isPressed) {
         if (mState != STATE_PROCESSING_KEYCODE) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 89206a7..ecb158b 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -72,19 +72,12 @@
         int uiCommand = tv().getSystemAudioMode()
                 ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
                 : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
-        sendUserControlPressedAndReleased(uiCommand);
+        sendUserControlPressedAndReleased(mAvrAddress, uiCommand);
 
         // Still return SUCCESS to callback.
         finishWithCallback(HdmiCec.RESULT_SUCCESS);
     }
 
-    private void sendUserControlPressedAndReleased(int uiCommand) {
-        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
-                getSourceAddress(), mAvrAddress, uiCommand));
-        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
-                getSourceAddress(), mAvrAddress));
-    }
-
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
         if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
@@ -109,7 +102,7 @@
 
             if ((tv().getSystemAudioMode() && mute) || (!tv().getSystemAudioMode() && !mute)) {
                 // Toggle AVR's mute status to match with the system audio status.
-                sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
+                sendUserControlPressedAndReleased(mAvrAddress, HdmiConstants.UI_COMMAND_MUTE);
             }
             finishWithCallback(HdmiCec.RESULT_SUCCESS);
         } else {
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
new file mode 100644
index 0000000..07c72f7
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -0,0 +1,222 @@
+/*
+ * 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.server.hdmi;
+
+import static com.android.server.hdmi.HdmiConstants.IRT_MS;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Feature action that transmits volume change to Audio Receiver.
+ * <p>
+ * This action is created when a user pressed volume up/down. However, Since Android only provides a
+ * listener for delta of some volume change, we will set a target volume, and check reported volume
+ * from Audio Receiver(AVR). If TV receives no &lt;Report Audio Status&gt; from AVR, this action
+ * will be finished in {@link #IRT_MS} * {@link #VOLUME_CHANGE_TIMEOUT_MAX_COUNT} (ms).
+ */
+final class VolumeControlAction extends FeatureAction {
+    private static final String TAG = "VolumeControlAction";
+
+    private static final int VOLUME_MUTE = 101;
+    private static final int VOLUME_RESTORE = 102;
+    private static final int MAX_VOLUME = 100;
+    private static final int MIN_VOLUME = 0;
+
+    // State where to wait for <Report Audio Status>
+    private static final int STATE_WAIT_FOR_REPORT_VOLUME_STATUS = 1;
+
+    // Maximum count of time out used to finish volume action.
+    private static final int VOLUME_CHANGE_TIMEOUT_MAX_COUNT = 2;
+
+    private final int mAvrAddress;
+    private final int mTargetVolume;
+    private final boolean mIsVolumeUp;
+    private int mTimeoutCount;
+
+    /**
+     * Create a {@link VolumeControlAction} for mute/restore change
+     *
+     * @param source source device sending volume change
+     * @param avrAddress address of audio receiver
+     * @param mute whether to mute sound or not. {@code true} for mute on; {@code false} for mute
+     *            off, i.e restore volume
+     * @return newly created {@link VolumeControlAction}
+     */
+    public static VolumeControlAction ofMute(HdmiCecLocalDevice source, int avrAddress,
+            boolean mute) {
+        return new VolumeControlAction(source, avrAddress, mute ? VOLUME_MUTE : VOLUME_RESTORE,
+                false);
+    }
+
+    /**
+     * Create a {@link VolumeControlAction} for volume up/down change
+     *
+     * @param source source device sending volume change
+     * @param avrAddress address of audio receiver
+     * @param targetVolume target volume to be set to AVR. It should be in range of [0-100]
+     * @param isVolumeUp whether to volume up or not. {@code true} for volume up; {@code false} for
+     *            volume down
+     * @return newly created {@link VolumeControlAction}
+     */
+    public static VolumeControlAction ofVolumeChange(HdmiCecLocalDevice source, int avrAddress,
+            int targetVolume, boolean isVolumeUp) {
+        Preconditions.checkArgumentInRange(targetVolume, MIN_VOLUME, MAX_VOLUME, "volume");
+        return new VolumeControlAction(source, avrAddress, targetVolume, isVolumeUp);
+    }
+
+    /**
+     * Scale a custom volume value to cec volume scale.
+     *
+     * @param volume volume value in custom scale
+     * @param scale scale of volume (max volume)
+     * @return a volume scaled to cec volume range
+     */
+    public static int scaleToCecVolume(int volume, int scale) {
+        return (volume * MAX_VOLUME) / scale;
+    }
+
+    /**
+     * Scale a cec volume which is in range of 0 to 100 to custom volume level.
+     *
+     * @param cecVolume volume value in cec volume scale. It should be in a range of [0-100]
+     * @param scale scale of custom volume (max volume)
+     * @return a volume value scaled to custom volume range
+     */
+    public static int scaleToCustomVolume(int cecVolume, int scale) {
+        return (cecVolume * scale) / MAX_VOLUME;
+    }
+
+    private VolumeControlAction(HdmiCecLocalDevice source, int avrAddress, int targetVolume,
+            boolean isVolumeUp) {
+        super(source);
+
+        mAvrAddress = avrAddress;
+        mTargetVolume = targetVolume;
+        mIsVolumeUp = isVolumeUp;
+    }
+
+    @Override
+    boolean start() {
+        if (isForMute()) {
+            sendMuteChange(mTargetVolume == VOLUME_MUTE);
+            finish();
+            return true;
+        }
+
+        startVolumeChange();
+        return true;
+    }
+
+
+    private boolean isForMute() {
+        return mTargetVolume == VOLUME_MUTE || mTargetVolume == VOLUME_RESTORE;
+    }
+
+
+    private void startVolumeChange() {
+        mTimeoutCount = 0;
+        sendVolumeChange(mIsVolumeUp);
+        mState = STATE_WAIT_FOR_REPORT_VOLUME_STATUS;
+        addTimer(mState, IRT_MS);
+    }
+
+    private void sendVolumeChange(boolean up) {
+        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), mAvrAddress,
+                up ? HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP
+                        : HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN));
+    }
+
+    private void sendMuteChange(boolean mute) {
+        sendUserControlPressedAndReleased(mAvrAddress,
+                mute ? HdmiConstants.UI_COMMAND_MUTE_FUNCTION :
+                        HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION);
+    }
+
+    @Override
+    boolean processCommand(HdmiCecMessage cmd) {
+        if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) {
+            return false;
+        }
+
+        switch (cmd.getOpcode()) {
+            case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
+                handleReportAudioStatus(cmd);
+                return true;
+            case HdmiCec.MESSAGE_FEATURE_ABORT:
+                // TODO: handle feature abort.
+                finish();
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private void handleReportAudioStatus(HdmiCecMessage cmd) {
+        byte[] params = cmd.getParams();
+        if (params.length != 1) {
+            Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
+            return;
+        }
+
+        int volume = params[0] & 0x7F;
+        // Update volume with new value.
+        // Note that it will affect system volume change.
+        tv().setAudioStatus(false, volume);
+        if (mIsVolumeUp) {
+            if (mTargetVolume <= volume) {
+                finishWithVolumeChangeRelease();
+                return;
+            }
+        } else {
+            if (mTargetVolume >= volume) {
+                finishWithVolumeChangeRelease();
+                return;
+            }
+        }
+
+        // Clear action status and send another volume change command.
+        clear();
+        startVolumeChange();
+    }
+
+    private void finishWithVolumeChangeRelease() {
+        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+                getSourceAddress(), mAvrAddress));
+        finish();
+    }
+
+    @Override
+    void handleTimerEvent(int state) {
+        if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) {
+            return;
+        }
+
+        // If no report volume action after IRT * VOLUME_CHANGE_TIMEOUT_MAX_COUNT just stop volume
+        // action.
+        if (++mTimeoutCount == VOLUME_CHANGE_TIMEOUT_MAX_COUNT) {
+            finishWithVolumeChangeRelease();
+            return;
+        }
+
+        sendVolumeChange(mIsVolumeUp);
+        addTimer(mState, IRT_MS);
+    }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 6f1eb8f..0a07d57 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -280,6 +280,9 @@
      * @param delta The amount to adjust the volume by.
      */
     public void adjustVolumeBy(int delta, int flags) {
+        if (isPlaybackActive(false)) {
+            flags &= ~AudioManager.FLAG_PLAY_SOUND;
+        }
         if (mVolumeType == MediaSession.PLAYBACK_TYPE_LOCAL) {
             if (delta == 0) {
                 mAudioManager.adjustStreamVolume(mAudioStream, delta, flags);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a0cb098..832a3b6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1047,6 +1047,11 @@
     }
 
     private UserInfo createUserInternal(String name, int flags, int parentId) {
+        if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
+                UserManager.DISALLOW_ADD_USER, false)) {
+            Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
+            return null;
+        }
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         try {
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 1783327..e4992d0 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -123,8 +123,6 @@
 
     /**
      * @return The state of this Connection.
-     *
-     * @hide
      */
     public final int getState() {
         return mState;
@@ -275,6 +273,8 @@
 
     /**
      * TODO(santoscordon): Needs updated documentation.
+     *
+     * @hide
      */
     public final void conference() {
         Log.d(this, "conference");
@@ -285,9 +285,14 @@
      * Inform this Connection that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
+     * @hide
      */
-    public void setAudioState(CallAudioState state) {
+    public final void setAudioState(CallAudioState state) {
         Log.d(this, "setAudioState %s", state);
+        mCallAudioState = state;
+        for (Listener l : mListeners) {
+            l.onAudioStateChanged(this, state);
+        }
         onSetAudioState(state);
     }
 
@@ -319,18 +324,21 @@
      * Returns whether this connection is requesting that the system play a ringback tone
      * on its behalf.
      */
-    public boolean isRequestingRingback() {
+    public final boolean isRequestingRingback() {
         return mRequestingRingback;
     }
 
     /**
      * Returns whether this connection is a conference connection (has child connections).
      */
-    public boolean isConferenceConnection() {
+    public final boolean isConferenceConnection() {
         return !mChildConnections.isEmpty();
     }
 
-    public void setParentConnection(Connection parentConnection) {
+    /**
+     * TODO(santoscordon): Needs documentation.
+     */
+    public final void setParentConnection(Connection parentConnection) {
         Log.d(this, "parenting %s to %s", this, parentConnection);
         if (mParentConnection != parentConnection) {
             if (mParentConnection != null) {
@@ -347,18 +355,18 @@
         }
     }
 
-    public Connection getParentConnection() {
+    public final Connection getParentConnection() {
         return mParentConnection;
     }
 
-    public List<Connection> getChildConnections() {
+    public final List<Connection> getChildConnections() {
         return mChildConnections;
     }
 
     /**
      * Returns whether this connection is capable of being conferenced.
      */
-    public boolean isConferenceCapable() {
+    public final boolean isConferenceCapable() {
         return mIsConferenceCapable;
     }
 
@@ -367,7 +375,7 @@
      *
      * @param handle The new handle.
      */
-    protected void setHandle(Uri handle) {
+    public final void setHandle(Uri handle) {
         Log.d(this, "setHandle %s", handle);
         // TODO: Enforce super called
         mHandle = handle;
@@ -380,7 +388,7 @@
      * Sets state to active (e.g., an ongoing call where two or more parties can actively
      * communicate).
      */
-    protected void setActive() {
+    public final void setActive() {
         setRequestingRingback(false);
         setState(State.ACTIVE);
     }
@@ -388,21 +396,21 @@
     /**
      * Sets state to ringing (e.g., an inbound ringing call).
      */
-    protected void setRinging() {
+    public final void setRinging() {
         setState(State.RINGING);
     }
 
     /**
      * Sets state to dialing (e.g., dialing an outbound call).
      */
-    protected void setDialing() {
+    public final void setDialing() {
         setState(State.DIALING);
     }
 
     /**
      * Sets state to be on hold.
      */
-    protected void setOnHold() {
+    public final void setOnHold() {
         setState(State.HOLDING);
     }
 
@@ -416,7 +424,7 @@
      *         {@link android.telephony.DisconnectCause}.
      * @param message Optional call-service-provided message about the disconnect.
      */
-    protected void setDisconnected(int cause, String message) {
+    public final void setDisconnected(int cause, String message) {
         setState(State.DISCONNECTED);
         Log.d(this, "Disconnected with cause %d message %s", cause, message);
         for (Listener l : mListeners) {
@@ -430,7 +438,7 @@
      *
      * @param ringback Whether the ringback tone is to be played.
      */
-    protected void setRequestingRingback(boolean ringback) {
+    public final void setRequestingRingback(boolean ringback) {
         if (mRequestingRingback != ringback) {
             mRequestingRingback = ringback;
             for (Listener l : mListeners) {
@@ -442,7 +450,7 @@
     /**
      * TODO(santoscordon): Needs documentation.
      */
-    protected void setIsConferenceCapable(boolean isConferenceCapable) {
+    public final void setIsConferenceCapable(boolean isConferenceCapable) {
         if (mIsConferenceCapable != isConferenceCapable) {
             mIsConferenceCapable = isConferenceCapable;
             for (Listener l : mListeners) {
@@ -454,7 +462,7 @@
     /**
      * TODO(santoscordon): Needs documentation.
      */
-    protected void setDestroyed() {
+    public final void setDestroyed() {
         // It is possible that onDestroy() will trigger the listener to remove itself which will
         // result in a concurrent modification exception. To counteract this we make a copy of the
         // listeners and iterate on that.
@@ -466,46 +474,32 @@
     }
 
     /**
-     * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
-     * has a new value.
-     *
-     * @param state The new call audio state.
-     */
-    protected void onSetAudioState(CallAudioState state) {
-        // TODO: Enforce super called
-        mCallAudioState = state;
-        for (Listener l : mListeners) {
-            l.onAudioStateChanged(this, state);
-        }
-    }
-
-    /**
      * Notifies this Connection and listeners of a change in the current signal levels
      * for the underlying data transport.
      *
      * @param details A {@link android.os.Bundle} containing details of the current level.
      */
-    protected void onSetSignal(Bundle details) {
-        // TODO: Enforce super called
+    public final void setSignal(Bundle details) {
         for (Listener l : mListeners) {
             l.onSignalChanged(this, details);
         }
     }
 
     /**
+     * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
+     * has a new value.
+     *
+     * @param state The new call audio state.
+     */
+    protected void onSetAudioState(CallAudioState state) {}
+
+    /**
      * Notifies this Connection of an internal state change. This method is called before the
-     * state is actually changed. Overriding implementations must call
-     * {@code super.onSetState(state)}.
+     * state is actually changed.
      *
      * @param state The new state, a {@link Connection.State} member.
      */
-    protected void onSetState(int state) {
-        // TODO: Enforce super called
-        this.mState = state;
-        for (Listener l : mListeners) {
-            l.onStateChanged(this, state);
-        }
-    }
+    protected void onSetState(int state) {}
 
     /**
      * Notifies this Connection of a request to play a DTMF tone.
@@ -585,6 +579,10 @@
 
     private void setState(int state) {
         Log.d(this, "setState: %s", stateToString(state));
+        this.mState = state;
+        for (Listener l : mListeners) {
+            l.onStateChanged(this, state);
+        }
         onSetState(state);
     }
 }