Merge "Updated some effects and notifications"
diff --git a/api/current.txt b/api/current.txt
index 5418072..3503fb3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18024,7 +18024,6 @@
 
   public abstract interface SynthesisCallback {
     method public abstract int audioAvailable(byte[], int, int);
-    method public abstract int completeAudioAvailable(int, int, int, byte[], int, int);
     method public abstract int done();
     method public abstract void error();
     method public abstract int getMaxBufferSize();
@@ -22080,6 +22079,7 @@
     method public void buildDrawingCache();
     method public void buildDrawingCache(boolean);
     method public void buildLayer();
+    method protected boolean canResolveLayoutDirection();
     method public boolean canScrollHorizontally(int);
     method public boolean canScrollVertically(int);
     method public void cancelLongPress();
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index bbf6b14e..e9ee95d 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -17,19 +17,135 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
-#include <cutils/properties.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/route.h>
 
+#define LOG_TAG "ip-up-vpn"
+#include <cutils/log.h>
+
+#define DIR "/data/misc/vpn/"
+
+static const char *env(const char *name) {
+    const char *value = getenv(name);
+    return value ? value : "";
+}
+
+static int set_address(struct sockaddr *sa, const char *address) {
+    sa->sa_family = AF_INET;
+    return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/*
+ * The primary goal is to create a file with VPN parameters. Currently they
+ * are interface, addresses, routes, DNS servers, and search domains. Each
+ * parameter occupies one line in the file, and it can be an empty string or
+ * space-separated values. The order and the format must be consistent with
+ * com.android.server.connectivity.Vpn. Here is an example.
+ *
+ *   ppp0
+ *   192.168.1.100/24
+ *   0.0.0.0/0
+ *   192.168.1.1 192.168.1.2
+ *   example.org
+ *
+ * The secondary goal is to unify the outcome of VPN. The current baseline
+ * is to have an interface configured with the given address and netmask
+ * and maybe add a host route to protect the tunnel. PPP-based VPN already
+ * does this, but others might not. Routes, DNS servers, and search domains
+ * are handled by the framework since they can be overridden by the users.
+ */
 int main(int argc, char **argv)
 {
-    if (argc > 1 && strlen(argv[1]) > 0) {
-        char dns[PROPERTY_VALUE_MAX];
-        char *dns1 = getenv("DNS1");
-        char *dns2 = getenv("DNS2");
+    FILE *state = fopen(DIR ".tmp", "wb");
+    if (!state) {
+        LOGE("Cannot create state: %s", strerror(errno));
+        return 1;
+    }
 
-        snprintf(dns, sizeof(dns), "%s %s", dns1 ? dns1 : "", dns2 ? dns2 : "");
-        property_set("vpn.dns", dns);
-        property_set("vpn.via", argv[1]);
+    if (argc >= 6) {
+        /* Invoked by pppd. */
+        fprintf(state, "%s\n", argv[1]);
+        fprintf(state, "%s/32\n", argv[4]);
+        fprintf(state, "0.0.0.0/0\n");
+        fprintf(state, "%s %s\n", env("DNS1"), env("DNS2"));
+        fprintf(state, "\n");
+    } else if (argc == 2) {
+        /* Invoked by racoon. */
+        const char *interface = env("INTERFACE");
+        const char *address = env("INTERNAL_ADDR4");
+        const char *routes = env("SPLIT_INCLUDE_CIDR");
+
+        int s = socket(AF_INET, SOCK_DGRAM, 0);
+        struct rtentry rt;
+        struct ifreq ifr;
+
+        memset(&rt, 0, sizeof(rt));
+        memset(&ifr, 0, sizeof(ifr));
+
+        /* Remove the old host route. There could be more than one. */
+        rt.rt_flags |= RTF_UP | RTF_HOST;
+        if (set_address(&rt.rt_dst, env("REMOTE_ADDR"))) {
+            while (!ioctl(s, SIOCDELRT, &rt));
+        }
+        if (errno != ESRCH) {
+            LOGE("Cannot remove host route: %s", strerror(errno));
+            return 1;
+        }
+
+        /* Create a new host route. */
+        rt.rt_flags |= RTF_GATEWAY;
+        if (!set_address(&rt.rt_gateway, argv[1]) ||
+                (ioctl(s, SIOCADDRT, &rt) && errno != EEXIST)) {
+            LOGE("Cannot create host route: %s", strerror(errno));
+            return 1;
+        }
+
+        /* Bring up the interface. */
+        ifr.ifr_flags = IFF_UP;
+        strncpy(ifr.ifr_name, interface, IFNAMSIZ);
+        if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
+            LOGE("Cannot bring up %s: %s", interface, strerror(errno));
+            return 1;
+        }
+
+        /* Set the address. */
+        if (!set_address(&ifr.ifr_addr, address) ||
+                ioctl(s, SIOCSIFADDR, &ifr)) {
+            LOGE("Cannot set address: %s", strerror(errno));
+            return 1;
+        }
+
+        /* Set the netmask. */
+        if (!set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4")) ||
+                ioctl(s, SIOCSIFNETMASK, &ifr)) {
+            LOGE("Cannot set netmask: %s", strerror(errno));
+            return 1;
+        }
+
+        /* TODO: Send few packets to trigger phase 2? */
+
+        fprintf(state, "%s\n", interface);
+        fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4"));
+        fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0");
+        fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST"));
+        fprintf(state, "%s\n", env("DEFAULT_DOMAIN"));
+    } else {
+        LOGE("Cannot parse parameters");
+        return 1;
+    }
+
+    fclose(state);
+    if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) {
+        LOGE("Cannot write state: %s", strerror(errno));
+        return 1;
     }
     return 0;
 }
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 3447e76c..44e7e52 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -98,11 +98,8 @@
     }
     
     @Override public boolean onTextContextMenuItem(int id) {
-        // Horrible hack: select word option has to be handled by original view to work.
-        if (mIME != null && id != android.R.id.startSelectingText) {
-            if (mIME.onExtractTextContextMenuItem(id)) {
-                return true;
-            }
+        if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
+            return true;
         }
         return super.onTextContextMenuItem(id);
     }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d6f5643..d95fc8d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -100,7 +100,7 @@
 
     void setDataDependency(int networkType, boolean met);
 
-    void protectVpn(in ParcelFileDescriptor socket);
+    boolean protectVpn(in ParcelFileDescriptor socket);
 
     boolean prepareVpn(String oldPackage, String newPackage);
 
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index f2f0e82..9826bec 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -57,16 +57,16 @@
     private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
     private ProxyProperties mHttpProxy;
 
-    public static class CompareAddressesResult {
-        public ArrayList<LinkAddress> removed = new ArrayList<LinkAddress>();
-        public ArrayList<LinkAddress> added = new ArrayList<LinkAddress>();
+    public static class CompareResult<T> {
+        public ArrayList<T> removed = new ArrayList<T>();
+        public ArrayList<T> added = new ArrayList<T>();
 
         @Override
         public String toString() {
-            String retVal = "removedAddresses=[";
-            for (LinkAddress addr : removed) retVal += addr.toString() + ",";
-            retVal += "] addedAddresses=[";
-            for (LinkAddress addr : added) retVal += addr.toString() + ",";
+            String retVal = "removed=[";
+            for (T addr : removed) retVal += addr.toString() + ",";
+            retVal += "] added=[";
+            for (T addr : added) retVal += addr.toString() + ",";
             retVal += "]";
             return retVal;
         }
@@ -263,10 +263,10 @@
      * mLinkAddress which would then result in target and mLinkAddresses
      * being the same list.
      *
-     * @param target is a new list of addresses
+     * @param target is a LinkProperties with the new list of addresses
      * @return the removed and added lists.
      */
-    public CompareAddressesResult compareAddresses(LinkProperties target) {
+    public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
         /*
          * Duplicate the LinkAddresses into removed, we will be removing
          * address which are common between mLinkAddresses and target
@@ -274,17 +274,81 @@
          * are in target but not in mLinkAddresses are placed in the
          * addedAddresses.
          */
-        CompareAddressesResult result = new CompareAddressesResult();
+        CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
         result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
         result.added.clear();
-        for (LinkAddress newAddress : target.getLinkAddresses()) {
-            if (! result.removed.remove(newAddress)) {
-                result.added.add(newAddress);
+        if (target != null) {
+            for (LinkAddress newAddress : target.getLinkAddresses()) {
+                if (! result.removed.remove(newAddress)) {
+                    result.added.add(newAddress);
+                }
             }
         }
         return result;
     }
 
+    /**
+     * Return two lists, a list of dns addresses that would be removed from
+     * mDnses and a list of addresses that would be added to
+     * mDnses which would then result in target and mDnses
+     * being the same list.
+     *
+     * @param target is a LinkProperties with the new list of dns addresses
+     * @return the removed and added lists.
+     */
+    public CompareResult<InetAddress> compareDnses(LinkProperties target) {
+        /*
+         * Duplicate the InetAddresses into removed, we will be removing
+         * dns address which are common between mDnses and target
+         * leaving the addresses that are different. And dns address which
+         * are in target but not in mDnses are placed in the
+         * addedAddresses.
+         */
+        CompareResult<InetAddress> result = new CompareResult<InetAddress>();
+
+        result.removed = new ArrayList<InetAddress>(mDnses);
+        result.added.clear();
+        if (target != null) {
+            for (InetAddress newAddress : target.getDnses()) {
+                if (! result.removed.remove(newAddress)) {
+                    result.added.add(newAddress);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Return two lists, a list of routes that would be removed from
+     * mRoutes and a list of routes that would be added to
+     * mRoutes which would then result in target and mRoutes
+     * being the same list.
+     *
+     * @param target is a LinkProperties with the new list of routes
+     * @return the removed and added lists.
+     */
+    public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
+        /*
+         * Duplicate the RouteInfos into removed, we will be removing
+         * routes which are common between mDnses and target
+         * leaving the routes that are different. And route address which
+         * are in target but not in mRoutes are placed in added.
+         */
+        CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
+
+        result.removed = new ArrayList<RouteInfo>(mRoutes);
+        result.added.clear();
+        if (target != null) {
+            for (RouteInfo r : target.getRoutes()) {
+                if (! result.removed.remove(r)) {
+                    result.added.add(r);
+                }
+            }
+        }
+        return result;
+    }
+
+
     @Override
     /**
      * generate hashcode based on significant fields
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 9381f1d..1ef0d9d 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,6 +18,7 @@
 
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
@@ -38,41 +39,69 @@
  */
 public class NetworkTemplate implements Parcelable {
 
+    /** {@hide} */
+    public static final int MATCH_MOBILE_ALL = 1;
+    /** {@hide} */
+    public static final int MATCH_MOBILE_3G_LOWER = 2;
+    /** {@hide} */
+    public static final int MATCH_MOBILE_4G = 3;
+    /** {@hide} */
+    public static final int MATCH_WIFI = 4;
+    /** {@hide} */
+    public static final int MATCH_ETHERNET = 5;
+
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
      * networks together. Only uses statistics for requested IMSI.
      */
-    public static final int MATCH_MOBILE_ALL = 1;
+    public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
+        return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
+    }
 
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
      * networks together that roughly meet a "3G" definition, or lower. Only
      * uses statistics for requested IMSI.
      */
-    public static final int MATCH_MOBILE_3G_LOWER = 2;
+    public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
+        return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId);
+    }
 
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
      * networks together that meet a "4G" definition. Only uses statistics for
      * requested IMSI.
      */
-    public static final int MATCH_MOBILE_4G = 3;
+    public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
+        return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId);
+    }
 
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
      * networks together.
      */
-    public static final int MATCH_WIFI = 4;
+    public static NetworkTemplate buildTemplateWifi() {
+        return new NetworkTemplate(MATCH_WIFI, null);
+    }
 
-    final int mMatchRule;
-    final String mSubscriberId;
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
+     * networks together.
+     */
+    public static NetworkTemplate buildTemplateEthernet() {
+        return new NetworkTemplate(MATCH_ETHERNET, null);
+    }
 
+    private final int mMatchRule;
+    private final String mSubscriberId;
+
+    /** {@hide} */
     public NetworkTemplate(int matchRule, String subscriberId) {
         this.mMatchRule = matchRule;
         this.mSubscriberId = subscriberId;
     }
 
-    public NetworkTemplate(Parcel in) {
+    private NetworkTemplate(Parcel in) {
         mMatchRule = in.readInt();
         mSubscriberId = in.readString();
     }
@@ -110,10 +139,12 @@
         return false;
     }
 
+    /** {@hide} */
     public int getMatchRule() {
         return mMatchRule;
     }
 
+    /** {@hide} */
     public String getSubscriberId() {
         return mSubscriberId;
     }
@@ -131,6 +162,8 @@
                 return matchesMobile4g(ident);
             case MATCH_WIFI:
                 return matchesWifi(ident);
+            case MATCH_ETHERNET:
+                return matchesEthernet(ident);
             default:
                 throw new IllegalArgumentException("unknown network template");
         }
@@ -190,7 +223,17 @@
         return false;
     }
 
-    public static String getMatchRuleName(int matchRule) {
+    /**
+     * Check if matches Ethernet network template.
+     */
+    private boolean matchesEthernet(NetworkIdentity ident) {
+        if (ident.mType == TYPE_ETHERNET) {
+            return true;
+        }
+        return false;
+    }
+
+    private static String getMatchRuleName(int matchRule) {
         switch (matchRule) {
             case MATCH_MOBILE_3G_LOWER:
                 return "MOBILE_3G_LOWER";
@@ -200,6 +243,8 @@
                 return "MOBILE_ALL";
             case MATCH_WIFI:
                 return "WIFI";
+            case MATCH_ETHERNET:
+                return "ETHERNET";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 8e5ddda..275f32a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -43,6 +43,7 @@
     private final InetAddress mGateway;
 
     private final boolean mIsDefault;
+    private final boolean mIsHost;
 
     public RouteInfo(LinkAddress destination, InetAddress gateway) {
         if (destination == null) {
@@ -68,6 +69,7 @@
                 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
         mGateway = gateway;
         mIsDefault = isDefault();
+        mIsHost = isHost();
     }
 
     public RouteInfo(InetAddress gateway) {
@@ -88,6 +90,10 @@
         }
     }
 
+    private boolean isHost() {
+        return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY));
+    }
+
     private boolean isDefault() {
         boolean val = false;
         if (mGateway != null) {
@@ -100,6 +106,7 @@
         return val;
     }
 
+
     public LinkAddress getDestination() {
         return mDestination;
     }
@@ -112,6 +119,10 @@
         return mIsDefault;
     }
 
+    public boolean isHostRoute() {
+        return mIsHost;
+    }
+
     public String toString() {
         String val = "";
         if (mDestination != null) val = mDestination.toString();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f799af3..f3bcedb 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -283,6 +283,13 @@
          */
         public static final String IS_DRM = "is_drm";
 
+        /**
+         * Used by the media scanner to suppress files from being processed as media files.
+         *
+         * <P>Type: INTEGER (boolean)</P>
+         * @hide
+         */
+        public static final String NO_MEDIA = "no_media";
      }
 
     /**
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index 1210941..dea708a 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -31,8 +31,7 @@
 
     private static final int SYNTHESIS_START = 1;
     private static final int SYNTHESIS_DATA_AVAILABLE = 2;
-    private static final int SYNTHESIS_COMPLETE_DATA_AVAILABLE = 3;
-    private static final int SYNTHESIS_DONE = 4;
+    private static final int SYNTHESIS_DONE = 3;
 
     private static final int PLAY_AUDIO = 5;
     private static final int PLAY_SILENCE = 6;
@@ -120,10 +119,6 @@
         mQueue.add(new ListEntry(SYNTHESIS_DATA_AVAILABLE, token));
     }
 
-    void enqueueSynthesisCompleteDataAvailable(SynthesisMessageParams token) {
-        mQueue.add(new ListEntry(SYNTHESIS_COMPLETE_DATA_AVAILABLE, token));
-    }
-
     void enqueueSynthesisDone(SynthesisMessageParams token) {
         mQueue.add(new ListEntry(SYNTHESIS_DONE, token));
     }
@@ -280,8 +275,6 @@
             handleSynthesisDataAvailable(msg);
         } else if (entry.mWhat == SYNTHESIS_DONE) {
             handleSynthesisDone(msg);
-        } else if (entry.mWhat == SYNTHESIS_COMPLETE_DATA_AVAILABLE) {
-            handleSynthesisCompleteDataAvailable(msg);
         } else if (entry.mWhat == PLAY_AUDIO) {
             handleAudio(msg);
         } else if (entry.mWhat == PLAY_SILENCE) {
@@ -424,54 +417,11 @@
             return;
         }
 
-        final AudioTrack track = params.mAudioTrack;
+        final AudioTrack audioTrack = params.mAudioTrack;
         final int bytesPerFrame = getBytesPerFrame(params.mAudioFormat);
         final int lengthInBytes = params.mBytesWritten;
+        final int lengthInFrames = lengthInBytes / bytesPerFrame;
 
-        blockUntilDone(track, bytesPerFrame, lengthInBytes);
-    }
-
-    private void handleSynthesisCompleteDataAvailable(MessageParams msg) {
-        final SynthesisMessageParams params = (SynthesisMessageParams) msg;
-        if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
-
-        params.mLogger.onPlaybackStart();
-
-        // Channel config and bytes per frame are checked before
-        // this message is sent.
-        int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
-        int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(params.mAudioFormat);
-
-        SynthesisMessageParams.ListEntry entry = params.getNextBuffer();
-
-        if (entry == null) {
-            Log.w(TAG, "completeDataAvailable : No buffers available to play.");
-            return;
-        }
-
-        final AudioTrack audioTrack = new AudioTrack(params.mStreamType, params.mSampleRateInHz,
-                channelConfig, params.mAudioFormat, entry.mLength, AudioTrack.MODE_STATIC);
-
-        // So that handleDone can access this correctly.
-        params.mAudioTrack = audioTrack;
-
-        try {
-            audioTrack.write(entry.mBytes, entry.mOffset, entry.mLength);
-            setupVolume(audioTrack, params.mVolume, params.mPan);
-            audioTrack.play();
-            blockUntilDone(audioTrack, bytesPerFrame, entry.mLength);
-            if (DBG) Log.d(TAG, "Wrote data to audio track successfully : " + entry.mLength);
-        } catch (IllegalStateException ex) {
-            Log.e(TAG, "Playback error", ex);
-        } finally {
-            handleSynthesisDone(msg);
-        }
-    }
-
-
-    private static void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame,
-            int lengthInBytes) {
-        int lengthInFrames = lengthInBytes / bytesPerFrame;
         int currentPosition = 0;
         while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
             if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 4f4b3fb..5808919 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -187,37 +187,6 @@
         }
     }
 
-    @Override
-    public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
-            byte[] buffer, int offset, int length) {
-        synchronized (mStateLock) {
-            if (mStopped) {
-                if (DBG) Log.d(TAG, "Request has been aborted.");
-                return TextToSpeech.ERROR;
-            }
-        }
-        FileOutputStream out = null;
-        try {
-            out = new FileOutputStream(mFileName);
-            out.write(makeWavHeader(sampleRateInHz, audioFormat, channelCount, length));
-            out.write(buffer, offset, length);
-            mDone = true;
-            return TextToSpeech.SUCCESS;
-        } catch (IOException ex) {
-            Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
-            mFileName.delete();
-            return TextToSpeech.ERROR;
-        } finally {
-            try {
-                if (out != null) {
-                    out.close();
-                }
-            } catch (IOException ex) {
-                Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
-            }
-        }
-    }
-
     private byte[] makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
             int dataLength) {
         // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 38030a6..04bd745 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -53,8 +53,7 @@
 
     // Handler associated with a thread that plays back audio requests.
     private final AudioPlaybackHandler mAudioTrackHandler;
-    // A request "token", which will be non null after start() or
-    // completeAudioAvailable() have been called.
+    // A request "token", which will be non null after start() has been called.
     private SynthesisMessageParams mToken = null;
     // Whether this request has been stopped. This is useful for keeping
     // track whether stop() has been called before start(). In all other cases,
@@ -206,35 +205,4 @@
         stop();
     }
 
-    @Override
-    public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
-            byte[] buffer, int offset, int length) {
-        int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
-        if (channelConfig == 0) {
-            Log.e(TAG, "Unsupported number of channels :" + channelCount);
-            return TextToSpeech.ERROR;
-        }
-
-        int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(audioFormat);
-        if (bytesPerFrame < 0) {
-            Log.e(TAG, "Unsupported audio format :" + audioFormat);
-            return TextToSpeech.ERROR;
-        }
-
-        synchronized (mStateLock) {
-            if (mStopped) {
-                return TextToSpeech.ERROR;
-            }
-            SynthesisMessageParams params = new SynthesisMessageParams(
-                    mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
-                    mDispatcher, mCallingApp, mLogger);
-            params.addBuffer(buffer, offset, length);
-
-            mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
-            mToken = params;
-        }
-
-        return TextToSpeech.SUCCESS;
-    }
-
 }
diff --git a/core/java/android/speech/tts/SynthesisCallback.java b/core/java/android/speech/tts/SynthesisCallback.java
index 1b80e40..d70c371d 100644
--- a/core/java/android/speech/tts/SynthesisCallback.java
+++ b/core/java/android/speech/tts/SynthesisCallback.java
@@ -22,19 +22,16 @@
  * {@link #start}, then {@link #audioAvailable} until all audio has been provided, then finally
  * {@link #done}.
  *
- * Alternatively, the engine can provide all the audio at once, by using
- * {@link #completeAudioAvailable}.
  *
  * {@link #error} can be called at any stage in the synthesis process to
- * indicate that an error has occured, but if the call is made after a call
- * to {@link #done} or {@link #completeAudioAvailable} it might be discarded.
+ * indicate that an error has occurred, but if the call is made after a call
+ * to {@link #done}, it might be discarded.
  */
 public interface SynthesisCallback {
     /**
      * @return the maximum number of bytes that the TTS engine can pass in a single call of
-     *         {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}.
-     *         Calls to {@link #audioAvailable} with data lengths larger than this
-     *         value will not succeed.
+     *         {@link #audioAvailable}. Calls to {@link #audioAvailable} with data lengths
+     *         larger than this value will not succeed.
      */
     public int getMaxBufferSize();
 
@@ -69,23 +66,6 @@
     public int audioAvailable(byte[] buffer, int offset, int length);
 
     /**
-     * The service can call this method instead of using {@link #start}, {@link #audioAvailable}
-     * and {@link #done} if all the audio data is available in a single buffer.
-     *
-     * @param sampleRateInHz Sample rate in HZ of the generated audio.
-     * @param audioFormat Audio format of the generated audio. Must be one of
-     *         the ENCODING_ constants defined in {@link android.media.AudioFormat}.
-     * @param channelCount The number of channels. Must be {@code 1} or {@code 2}.
-     * @param buffer The generated audio data. This method will not hold on to {@code buffer},
-     *         so the caller is free to modify it after this method returns.
-     * @param offset The offset into {@code buffer} where the audio data starts.
-     * @param length The number of bytes of audio data in {@code buffer}.
-     * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
-     */
-    public int completeAudioAvailable(int sampleRateInHz, int audioFormat,
-            int channelCount, byte[] buffer, int offset, int length);
-
-    /**
      * The service should call this method when all the synthesized audio for a request has
      * been passed to {@link #audioAvailable}.
      *
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 757a8c3..5a244f1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -226,7 +226,17 @@
      */
     public static Metrics isBoring(CharSequence text,
                                    TextPaint paint) {
-        return isBoring(text, paint, null);
+        return isBoring(text, paint, TextDirectionHeuristics.FIRSTSTRONG_LTR, null);
+    }
+
+    /**
+     * Returns null if not boring; the width, ascent, and descent if boring.
+     * @hide
+     */
+    public static Metrics isBoring(CharSequence text,
+                                   TextPaint paint,
+                                   TextDirectionHeuristic textDir) {
+        return isBoring(text, paint, textDir, null);
     }
 
     /**
@@ -235,6 +245,17 @@
      * if boring.
      */
     public static Metrics isBoring(CharSequence text, TextPaint paint, Metrics metrics) {
+        return isBoring(text, paint, TextDirectionHeuristics.FIRSTSTRONG_LTR, metrics);
+    }
+
+    /**
+     * Returns null if not boring; the width, ascent, and descent in the
+     * provided Metrics object (or a new one if the provided one was null)
+     * if boring.
+     * @hide
+     */
+    public static Metrics isBoring(CharSequence text, TextPaint paint,
+            TextDirectionHeuristic textDir, Metrics metrics) {
         char[] temp = TextUtils.obtain(500);
         int length = text.length();
         boolean boring = true;
@@ -258,6 +279,11 @@
                     break outer;
                 }
             }
+
+            if (textDir.isRtl(temp, 0, n)) {
+               boring = false;
+               break outer;
+            }
         }
 
         TextUtils.recycle(temp);
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index f196b34..cb96969 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -75,12 +75,31 @@
                          float spacingmult, float spacingadd,
                          boolean includepad,
                          TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
-        super((ellipsize == null) 
-                ? display 
-                : (display instanceof Spanned) 
-                    ? new SpannedEllipsizer(display) 
+        this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+    }
+
+    /**
+     * Make a layout for the transformed text (password transformation
+     * being the primary example of a transformation)
+     * that will be updated as the base text is changed.
+     * If ellipsize is non-null, the Layout will ellipsize the text
+     * down to ellipsizedWidth.
+     * *
+     * *@hide
+     */
+    public DynamicLayout(CharSequence base, CharSequence display,
+                         TextPaint paint,
+                         int width, Alignment align, TextDirectionHeuristic textDir,
+                         float spacingmult, float spacingadd,
+                         boolean includepad,
+                         TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+        super((ellipsize == null)
+                ? display
+                : (display instanceof Spanned)
+                    ? new SpannedEllipsizer(display)
                     : new Ellipsizer(display),
-              paint, width, align, spacingmult, spacingadd);
+              paint, width, align, textDir, spacingmult, spacingadd);
 
         mBase = base;
         mDisplay = display;
@@ -259,7 +278,7 @@
             reflowed = new StaticLayout(true);
 
         reflowed.generate(text, where, where + after,
-                getPaint(), getWidth(), getAlignment(),
+                getPaint(), getWidth(), getAlignment(), getTextDirectionHeuristic(),
                 getSpacingMultiplier(), getSpacingAdd(),
                 false, true, mEllipsizedWidth, mEllipsizeAt);
         int n = reflowed.getLineCount();
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index aae9ccf..eabeef0 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,8 +16,6 @@
 
 package android.text;
 
-import com.android.internal.util.ArrayUtils;
-
 import android.emoji.EmojiFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -32,6 +30,8 @@
 import android.text.style.ReplacementSpan;
 import android.text.style.TabStopSpan;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.util.Arrays;
 
 /**
@@ -113,6 +113,29 @@
     protected Layout(CharSequence text, TextPaint paint,
                      int width, Alignment align,
                      float spacingMult, float spacingAdd) {
+        this(text, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                spacingMult, spacingAdd);
+    }
+
+    /**
+     * Subclasses of Layout use this constructor to set the display text,
+     * width, and other standard properties.
+     * @param text the text to render
+     * @param paint the default paint for the layout.  Styles can override
+     * various attributes of the paint.
+     * @param width the wrapping width for the text.
+     * @param align whether to left, right, or center the text.  Styles can
+     * override the alignment.
+     * @param spacingMult factor by which to scale the font size to get the
+     * default line spacing
+     * @param spacingAdd amount to add to the default line spacing
+     *
+     * @hide
+     */
+    protected Layout(CharSequence text, TextPaint paint,
+                     int width, Alignment align, TextDirectionHeuristic textDir,
+                     float spacingMult, float spacingAdd) {
+
         if (width < 0)
             throw new IllegalArgumentException("Layout: " + width + " < 0");
 
@@ -133,6 +156,7 @@
         mSpacingMult = spacingMult;
         mSpacingAdd = spacingAdd;
         mSpannedText = text instanceof Spanned;
+        mTextDir = textDir;
     }
 
     /**
@@ -531,6 +555,14 @@
     }
 
     /**
+     * Return the heuristic used to determine paragraph text direction.
+     * @hide
+     */
+    public final TextDirectionHeuristic getTextDirectionHeuristic() {
+        return mTextDir;
+    }
+
+    /**
      * Return the number of lines of text in this layout.
      */
     public abstract int getLineCount();
@@ -1419,7 +1451,7 @@
         MeasuredText mt = MeasuredText.obtain();
         TextLine tl = TextLine.obtain();
         try {
-            mt.setPara(text, start, end, DIR_REQUEST_LTR);
+            mt.setPara(text, start, end, TextDirectionHeuristics.LTR);
             Directions directions;
             int dir;
             if (mt.mEasy) {
@@ -1769,6 +1801,7 @@
     private float mSpacingAdd;
     private static final Rect sTempRect = new Rect();
     private boolean mSpannedText;
+    private TextDirectionHeuristic mTextDir;
 
     public static final int DIR_LEFT_TO_RIGHT = 1;
     public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index a81be09..2920ac5 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -85,7 +85,7 @@
      * Analyzes text for bidirectional runs.  Allocates working buffers.
      */
     /* package */
-    void setPara(CharSequence text, int start, int end, int bidiRequest) {
+    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
         mText = text;
         mTextStart = start;
 
@@ -115,13 +115,29 @@
             }
         }
 
-        if (TextUtils.doesNotNeedBidi(mChars, 0, len)) {
+        if ((textDir == TextDirectionHeuristics.LTR ||
+                textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
+                textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
+                TextUtils.doesNotNeedBidi(mChars, 0, len)) {
             mDir = Layout.DIR_LEFT_TO_RIGHT;
             mEasy = true;
         } else {
             if (mLevels == null || mLevels.length < len) {
                 mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
             }
+            int bidiRequest;
+            if (textDir == TextDirectionHeuristics.LTR) {
+                bidiRequest = Layout.DIR_REQUEST_LTR;
+            } else if (textDir == TextDirectionHeuristics.RTL) {
+                bidiRequest = Layout.DIR_REQUEST_RTL;
+            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
+                bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
+            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
+                bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
+            } else {
+                boolean isRtl = textDir.isRtl(mChars, 0, len);
+                bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
+            }
             mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
             mEasy = false;
         }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9e48eff..f7b9502 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,8 +16,6 @@
 
 package android.text;
 
-import com.android.internal.util.ArrayUtils;
-
 import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.text.style.LeadingMarginSpan;
@@ -26,6 +24,8 @@
 import android.text.style.MetricAffectingSpan;
 import android.text.style.TabStopSpan;
 
+import com.android.internal.util.ArrayUtils;
+
 /**
  * StaticLayout is a Layout for text that will not be edited after it
  * is laid out.  Use {@link DynamicLayout} for text that may change.
@@ -46,6 +46,17 @@
              spacingmult, spacingadd, includepad);
     }
 
+    /**
+     * @hide
+     */
+    public StaticLayout(CharSequence source, TextPaint paint,
+            int width, Alignment align, TextDirectionHeuristic textDir,
+            float spacingmult, float spacingadd,
+            boolean includepad) {
+        this(source, 0, source.length(), paint, width, align, textDir,
+                spacingmult, spacingadd, includepad);
+    }
+
     public StaticLayout(CharSequence source, int bufstart, int bufend,
                         TextPaint paint, int outerwidth,
                         Alignment align,
@@ -55,9 +66,35 @@
              spacingmult, spacingadd, includepad, null, 0);
     }
 
+    /**
+     * @hide
+     */
+    public StaticLayout(CharSequence source, int bufstart, int bufend,
+            TextPaint paint, int outerwidth,
+            Alignment align, TextDirectionHeuristic textDir,
+            float spacingmult, float spacingadd,
+            boolean includepad) {
+        this(source, bufstart, bufend, paint, outerwidth, align, textDir,
+                spacingmult, spacingadd, includepad, null, 0);
+}
+
+    public StaticLayout(CharSequence source, int bufstart, int bufend,
+            TextPaint paint, int outerwidth,
+            Alignment align,
+            float spacingmult, float spacingadd,
+            boolean includepad,
+            TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+        this(source, bufstart, bufend, paint, outerwidth, align,
+                TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+    }
+
+    /**
+     * @hide
+     */
     public StaticLayout(CharSequence source, int bufstart, int bufend,
                         TextPaint paint, int outerwidth,
-                        Alignment align,
+                        Alignment align, TextDirectionHeuristic textDir,
                         float spacingmult, float spacingadd,
                         boolean includepad,
                         TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
@@ -66,7 +103,7 @@
                 : (source instanceof Spanned)
                     ? new SpannedEllipsizer(source)
                     : new Ellipsizer(source),
-              paint, outerwidth, align, spacingmult, spacingadd);
+              paint, outerwidth, align, textDir, spacingmult, spacingadd);
 
         /*
          * This is annoying, but we can't refer to the layout until
@@ -96,7 +133,7 @@
 
         mMeasured = MeasuredText.obtain();
 
-        generate(source, bufstart, bufend, paint, outerwidth, align,
+        generate(source, bufstart, bufend, paint, outerwidth, align, textDir,
                  spacingmult, spacingadd, includepad, includepad,
                  ellipsizedWidth, ellipsize);
 
@@ -116,7 +153,7 @@
 
     /* package */ void generate(CharSequence source, int bufStart, int bufEnd,
                         TextPaint paint, int outerWidth,
-                        Alignment align,
+                        Alignment align, TextDirectionHeuristic textDir,
                         float spacingmult, float spacingadd,
                         boolean includepad, boolean trackpad,
                         float ellipsizedWidth, TextUtils.TruncateAt ellipsize) {
@@ -157,7 +194,7 @@
                     LeadingMarginSpan lms = sp[i];
                     firstWidth -= sp[i].getLeadingMargin(true);
                     restWidth -= sp[i].getLeadingMargin(false);
-                    
+
                     // LeadingMarginSpan2 is odd.  The count affects all
                     // leading margin spans, not just this particular one,
                     // and start from the top of the span, not the top of the
@@ -195,7 +232,7 @@
                 }
             }
 
-            measured.setPara(source, paraStart, paraEnd, DIR_REQUEST_DEFAULT_LTR);
+            measured.setPara(source, paraStart, paraEnd, textDir);
             char[] chs = measured.mChars;
             float[] widths = measured.mWidths;
             byte[] chdirs = measured.mLevels;
diff --git a/core/java/android/text/TextDirectionHeuristic.java b/core/java/android/text/TextDirectionHeuristic.java
new file mode 100644
index 0000000..130f879
--- /dev/null
+++ b/core/java/android/text/TextDirectionHeuristic.java
@@ -0,0 +1,13 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.text;
+
+/**
+ * Interface for objects that guess at the paragraph direction by examining text.
+ *
+ * @hide
+ */
+public interface TextDirectionHeuristic {
+    /** @hide */ boolean isRtl(CharSequence text, int start, int end);
+    /** @hide */ boolean isRtl(char[] text, int start, int count);
+}
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
new file mode 100644
index 0000000..5f9ffc5
--- /dev/null
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -0,0 +1,310 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.text;
+
+
+/**
+ * Some objects that implement TextDirectionHeuristic.
+ * @hide
+ */
+public class TextDirectionHeuristics {
+
+    /** Always decides that the direction is left to right. */
+    public static final TextDirectionHeuristic LTR =
+        new TextDirectionHeuristicInternal(null /* no algorithm */, false);
+
+    /** Always decides that the direction is right to left. */
+    public static final TextDirectionHeuristic RTL =
+        new TextDirectionHeuristicInternal(null /* no algorithm */, true);
+
+    /**
+     * Determines the direction based on the first strong directional character,
+     * including bidi format chars, falling back to left to right if it
+     * finds none.  This is the default behavior of the Unicode Bidirectional
+     * Algorithm.
+     */
+    public static final TextDirectionHeuristic FIRSTSTRONG_LTR =
+        new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, false);
+
+    /**
+     * Determines the direction based on the first strong directional character,
+     * including bidi format chars, falling back to right to left if it
+     * finds none.  This is similar to the default behavior of the Unicode
+     * Bidirectional Algorithm, just with different fallback behavior.
+     */
+    public static final TextDirectionHeuristic FIRSTSTRONG_RTL =
+        new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
+
+    /**
+     * If the text contains any strong right to left non-format character, determines
+     * that the direction is right to left, falling back to left to right if it
+     * finds none.
+     */
+    public static final TextDirectionHeuristic ANYRTL_LTR =
+        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
+
+    /**
+     * If the text contains any strong left to right non-format character, determines
+     * that the direction is left to right, falling back to right to left if it
+     * finds none.
+     */
+    public static final TextDirectionHeuristic ANYLTR_RTL =
+        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_LTR, true);
+
+    /**
+     * Examines only the strong directional non-format characters, and if either
+     * left to right or right to left characters are 60% or more of this total,
+     * determines that the direction follows the majority of characters.  Falls
+     * back to left to right if neither direction meets this threshold.
+     */
+    public static final TextDirectionHeuristic CHARCOUNT_LTR =
+        new TextDirectionHeuristicInternal(CharCount.INSTANCE_DEFAULT, false);
+
+    /**
+     * Examines only the strong directional non-format characters, and if either
+     * left to right or right to left characters are 60% or more of this total,
+     * determines that the direction follows the majority of characters.  Falls
+     * back to right to left if neither direction meets this threshold.
+     */
+    public static final TextDirectionHeuristic CHARCOUNT_RTL =
+        new TextDirectionHeuristicInternal(CharCount.INSTANCE_DEFAULT, true);
+
+    private static enum TriState {
+        TRUE, FALSE, UNKNOWN;
+    }
+
+    /**
+     * Computes the text direction based on an algorithm.  Subclasses implement
+     * {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the
+     * direction from the text alone.
+     * @hide
+     */
+    public static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
+        private final TextDirectionAlgorithm mAlgorithm;
+
+        public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
+            mAlgorithm = algorithm;
+        }
+
+        /**
+         * Return true if the default text direction is rtl.
+         */
+        abstract protected boolean defaultIsRtl();
+
+        @Override
+        public boolean isRtl(CharSequence text, int start, int end) {
+            if (text == null || start < 0 || end < start || text.length() < end) {
+                throw new IllegalArgumentException();
+            }
+            if (mAlgorithm == null) {
+                return defaultIsRtl();
+            }
+            text = text.subSequence(start, end);
+            char[] chars = text.toString().toCharArray();
+            return doCheck(chars, 0, chars.length);
+        }
+
+        @Override
+        public boolean isRtl(char[] chars, int start, int count) {
+            if (chars == null || start < 0 || count < 0 || chars.length - count < start) {
+                throw new IllegalArgumentException();
+            }
+            if (mAlgorithm == null) {
+                return defaultIsRtl();
+            }
+            return doCheck(chars, start, count);
+        }
+
+        private boolean doCheck(char[] chars, int start, int count) {
+            switch(mAlgorithm.checkRtl(chars, start, count)) {
+                case TRUE:
+                    return true;
+                case FALSE:
+                    return false;
+                default:
+                    return defaultIsRtl();
+            }
+        }
+    }
+
+    private static class TextDirectionHeuristicInternal extends TextDirectionHeuristicImpl {
+        private final boolean mDefaultIsRtl;
+
+        private TextDirectionHeuristicInternal(TextDirectionAlgorithm algorithm,
+                boolean defaultIsRtl) {
+            super(algorithm);
+            mDefaultIsRtl = defaultIsRtl;
+        }
+
+        @Override
+        protected boolean defaultIsRtl() {
+            return mDefaultIsRtl;
+        }
+    }
+
+    private static TriState isRtlText(int directionality) {
+        switch (directionality) {
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+                return TriState.FALSE;
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+                return TriState.TRUE;
+            default:
+                return TriState.UNKNOWN;
+        }
+    }
+
+    private static TriState isRtlTextOrFormat(int directionality) {
+        switch (directionality) {
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+                return TriState.FALSE;
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+                return TriState.TRUE;
+            default:
+                return TriState.UNKNOWN;
+        }
+    }
+
+    /**
+     * Interface for an algorithm to guess the direction of a paragraph of text.
+     *
+     * @hide
+     */
+    public static interface TextDirectionAlgorithm {
+        /**
+         * Returns whether the range of text is RTL according to the algorithm.
+         *
+         * @hide
+         */
+        TriState checkRtl(char[] text, int start, int count);
+    }
+
+    /**
+     * Algorithm that uses the first strong directional character to determine
+     * the paragraph direction.  This is the standard Unicode Bidirectional
+     * algorithm.
+     *
+     * @hide
+     */
+    public static class FirstStrong implements TextDirectionAlgorithm {
+        @Override
+        public TriState checkRtl(char[] text, int start, int count) {
+            TriState result = TriState.UNKNOWN;
+            for (int i = start, e = start + count; i < e && result == TriState.UNKNOWN; ++i) {
+                result = isRtlTextOrFormat(Character.getDirectionality(text[i]));
+            }
+            return result;
+        }
+
+        private FirstStrong() {
+        }
+
+        public static final FirstStrong INSTANCE = new FirstStrong();
+    }
+
+    /**
+     * Algorithm that uses the presence of any strong directional non-format
+     * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
+     * direction of text.
+     *
+     * @hide
+     */
+    public static class AnyStrong implements TextDirectionAlgorithm {
+        private final boolean mLookForRtl;
+
+        @Override
+        public TriState checkRtl(char[] text, int start, int count) {
+            boolean haveUnlookedFor = false;
+            for (int i = start, e = start + count; i < e; ++i) {
+                switch (isRtlText(Character.getDirectionality(text[i]))) {
+                    case TRUE:
+                        if (mLookForRtl) {
+                            return TriState.TRUE;
+                        }
+                        haveUnlookedFor = true;
+                        break;
+                    case FALSE:
+                        if (!mLookForRtl) {
+                            return TriState.FALSE;
+                        }
+                        haveUnlookedFor = true;
+                        break;
+                    default:
+                        break;
+                }
+            }
+            if (haveUnlookedFor) {
+                return mLookForRtl ? TriState.FALSE : TriState.TRUE;
+            }
+            return TriState.UNKNOWN;
+        }
+
+        private AnyStrong(boolean lookForRtl) {
+            this.mLookForRtl = lookForRtl;
+        }
+
+        public static final AnyStrong INSTANCE_RTL = new AnyStrong(true);
+        public static final AnyStrong INSTANCE_LTR = new AnyStrong(false);
+    }
+
+    /**
+     * Algorithm that uses the relative proportion of strong directional
+     * characters (excluding LRE, LRO, RLE, RLO) to determine the direction
+     * of the paragraph, if the proportion exceeds a given threshold.
+     *
+     * @hide
+     */
+    public static class CharCount implements TextDirectionAlgorithm {
+        private final float mThreshold;
+
+        @Override
+        public TriState checkRtl(char[] text, int start, int count) {
+            int countLtr = 0;
+            int countRtl = 0;
+            for(int i = start, e = start + count; i < e; ++i) {
+                switch (isRtlText(Character.getDirectionality(text[i]))) {
+                    case TRUE:
+                        ++countLtr;
+                        break;
+                    case FALSE:
+                        ++countRtl;
+                        break;
+                    default:
+                        break;
+                }
+            }
+            int limit = (int)((countLtr + countRtl) * mThreshold);
+            if (limit > 0) {
+                if (countLtr > limit) {
+                    return TriState.FALSE;
+                }
+                if (countRtl > limit) {
+                    return TriState.TRUE;
+                }
+            }
+            return TriState.UNKNOWN;
+        }
+
+        private CharCount(float threshold) {
+            mThreshold = threshold;
+        }
+
+        public static CharCount withThreshold(float threshold) {
+            if (threshold < 0 || threshold > 1) {
+                throw new IllegalArgumentException();
+            }
+            if (threshold == DEFAULT_THRESHOLD) {
+                return INSTANCE_DEFAULT;
+            }
+            return new CharCount(threshold);
+        }
+
+        public static final float DEFAULT_THRESHOLD = 0.6f;
+        public static final CharCount INSTANCE_DEFAULT = new CharCount(DEFAULT_THRESHOLD);
+    }
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6741059..29c9853 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,9 +16,6 @@
 
 package android.text;
 
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -45,6 +42,9 @@
 import android.text.style.UnderlineSpan;
 import android.util.Printer;
 
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+
 import java.lang.reflect.Array;
 import java.util.Iterator;
 import java.util.regex.Pattern;
@@ -1001,13 +1001,37 @@
      * will be padded with zero-width spaces to preserve the original
      * length and offsets instead of truncating.
      * If <code>callback</code> is non-null, it will be called to
-     * report the start and end of the ellipsized range.
+     * report the start and end of the ellipsized range.  TextDirection
+     * is determined by the first strong directional character.
      */
     public static CharSequence ellipsize(CharSequence text,
                                          TextPaint paint,
                                          float avail, TruncateAt where,
                                          boolean preserveLength,
                                          EllipsizeCallback callback) {
+        return ellipsize(text, paint, avail, where, preserveLength, callback,
+                TextDirectionHeuristics.FIRSTSTRONG_LTR);
+    }
+
+    /**
+     * Returns the original text if it fits in the specified width
+     * given the properties of the specified Paint,
+     * or, if it does not fit, a copy with ellipsis character added
+     * at the specified edge or center.
+     * If <code>preserveLength</code> is specified, the returned copy
+     * will be padded with zero-width spaces to preserve the original
+     * length and offsets instead of truncating.
+     * If <code>callback</code> is non-null, it will be called to
+     * report the start and end of the ellipsized range.
+     *
+     * @hide
+     */
+    public static CharSequence ellipsize(CharSequence text,
+            TextPaint paint,
+            float avail, TruncateAt where,
+            boolean preserveLength,
+            EllipsizeCallback callback,
+            TextDirectionHeuristic textDir) {
         if (sEllipsis == null) {
             Resources r = Resources.getSystem();
             sEllipsis = r.getString(R.string.ellipsis);
@@ -1017,8 +1041,7 @@
 
         MeasuredText mt = MeasuredText.obtain();
         try {
-            float width = setPara(mt, paint, text, 0, text.length(),
-                    Layout.DIR_REQUEST_DEFAULT_LTR);
+            float width = setPara(mt, paint, text, 0, text.length(), textDir);
 
             if (width <= avail) {
                 if (callback != null) {
@@ -1108,11 +1131,20 @@
                                               TextPaint p, float avail,
                                               String oneMore,
                                               String more) {
+        return commaEllipsize(text, p, avail, oneMore, more,
+                TextDirectionHeuristics.FIRSTSTRONG_LTR);
+    }
+
+    /**
+     * @hide
+     */
+    public static CharSequence commaEllipsize(CharSequence text, TextPaint p,
+         float avail, String oneMore, String more, TextDirectionHeuristic textDir) {
 
         MeasuredText mt = MeasuredText.obtain();
         try {
             int len = text.length();
-            float width = setPara(mt, p, text, 0, len, Layout.DIR_REQUEST_DEFAULT_LTR);
+            float width = setPara(mt, p, text, 0, len, textDir);
             if (width <= avail) {
                 return text;
             }
@@ -1135,9 +1167,6 @@
             int count = 0;
             float[] widths = mt.mWidths;
 
-            int request = mt.mDir == 1 ? Layout.DIR_REQUEST_LTR :
-                Layout.DIR_REQUEST_RTL;
-
             MeasuredText tempMt = MeasuredText.obtain();
             for (int i = 0; i < len; i++) {
                 w += widths[i];
@@ -1155,7 +1184,7 @@
                     }
 
                     // XXX this is probably ok, but need to look at it more
-                    tempMt.setPara(format, 0, format.length(), request);
+                    tempMt.setPara(format, 0, format.length(), textDir);
                     float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
 
                     if (w + moreWid <= avail) {
@@ -1175,9 +1204,9 @@
     }
 
     private static float setPara(MeasuredText mt, TextPaint paint,
-            CharSequence text, int start, int end, int bidiRequest) {
+            CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
 
-        mt.setPara(text, start, end, bidiRequest);
+        mt.setPara(text, start, end, textDir);
 
         float width;
         Spanned sp = text instanceof Spanned ? (Spanned) text : null;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 74dc100..c8ff37a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,13 +16,6 @@
 
 package android.view;
 
-import android.util.FloatProperty;
-import android.util.LocaleUtil;
-import android.util.Property;
-import com.android.internal.R;
-import com.android.internal.util.Predicate;
-import com.android.internal.view.menu.MenuBuilder;
-
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -53,11 +46,14 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.LocaleUtil;
 import android.util.Log;
 import android.util.Pool;
 import android.util.Poolable;
 import android.util.PoolableManager;
 import android.util.Pools;
+import android.util.Property;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -72,6 +68,10 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.ScrollBarDrawable;
 
+import com.android.internal.R;
+import com.android.internal.util.Predicate;
+import com.android.internal.view.menu.MenuBuilder;
+
 import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -2493,12 +2493,6 @@
     private boolean mSendingHoverAccessibilityEvents;
 
     /**
-     * Undefined text direction (used by resolution algorithm).
-     * @hide
-     */
-    public static final int TEXT_DIRECTION_UNDEFINED = -1;
-
-    /**
      * Text direction is inherited thru {@link ViewGroup}
      * @hide
      */
@@ -2507,7 +2501,7 @@
     /**
      * Text direction is using "first strong algorithm". The first strong directional character
      * determines the paragraph direction. If there is no strong directional character, the
-     * paragraph direction is the view’s resolved ayout direction.
+     * paragraph direction is the view's resolved ayout direction.
      *
      * @hide
      */
@@ -2516,7 +2510,7 @@
     /**
      * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
      * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
-     * If there are neither, the paragraph direction is the view’s resolved layout direction.
+     * If there are neither, the paragraph direction is the view's resolved layout direction.
      *
      * @hide
      */
@@ -2560,7 +2554,6 @@
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "text", mapping = {
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
@@ -2568,21 +2561,25 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
     })
-    protected int mTextDirection = DEFAULT_TEXT_DIRECTION;
+    private int mTextDirection = DEFAULT_TEXT_DIRECTION;
 
     /**
-     * The resolved text direction. If resolution has not yet been done or has been reset, it will
-     * be equal to {@link #TEXT_DIRECTION_UNDEFINED}. Otherwise it will be either {@link #TEXT_DIRECTION_LTR}
-     * or {@link #TEXT_DIRECTION_RTL}.
+     * The resolved text direction.  This needs resolution if the value is
+     * TEXT_DIRECTION_INHERIT.  The resolution matches mTextDirection if that is
+     * not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent
+     * chain of the view.
      *
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "text", mapping = {
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_CHAR_COUNT, to = "CHAR_COUNT"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
     })
-    protected int mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+    private int mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
 
     /**
      * Consistency verifier for debugging purposes.
@@ -9066,11 +9063,20 @@
         // Set resolved depending on layout direction
         switch (getLayoutDirection()) {
             case LAYOUT_DIRECTION_INHERIT:
+                // We cannot do the resolution if there is no parent
+                if (mParent == null) return;
+
                 // If this is root view, no need to look at parent's layout dir.
-                if (mParent != null &&
-                        mParent instanceof ViewGroup &&
-                        ((ViewGroup) mParent).getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                    mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+                if (mParent instanceof ViewGroup) {
+                    ViewGroup viewGroup = ((ViewGroup) mParent);
+
+                    // Check if the parent view group can resolve
+                    if (! viewGroup.canResolveLayoutDirection()) {
+                        return;
+                    }
+                    if (viewGroup.getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                        mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+                    }
                 }
                 break;
             case LAYOUT_DIRECTION_RTL:
@@ -9132,6 +9138,15 @@
         recomputePadding();
     }
 
+    protected boolean canResolveLayoutDirection() {
+        switch (getLayoutDirection()) {
+            case LAYOUT_DIRECTION_INHERIT:
+                return (mParent != null);
+            default:
+                return true;
+        }
+    }
+
     /**
      * Reset the resolved layout direction.
      *
@@ -13048,43 +13063,41 @@
      *
      * @return the resolved text direction. Return one of:
      *
+     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_ANY_RTL},
+     * {@link #TEXT_DIRECTION_CHAR_COUNT},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      *
      * @hide
      */
     public int getResolvedTextDirection() {
-        if (!isResolvedTextDirection()) {
+        if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
             resolveTextDirection();
         }
         return mResolvedTextDirection;
     }
 
     /**
-     * Resolve the text direction. Classes that extend View and want to do a specific text direction
-     * resolution will need to implement this method and set the mResolvedTextDirection to
-     * either TEXT_DIRECTION_LTR if direction is LTR or TEXT_DIRECTION_RTL if
-     * direction is RTL.
+     * Resolve the text direction.
      */
     protected void resolveTextDirection() {
+        if (mTextDirection != TEXT_DIRECTION_INHERIT) {
+            mResolvedTextDirection = mTextDirection;
+            return;
+        }
+        if (mParent != null && mParent instanceof ViewGroup) {
+            mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
+            return;
+        }
+        mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
     }
 
     /**
-     * Return if the text direction has been resolved or not.
-     *
-     * @return true, if resolved and false if not resolved
-     *
-     * @hide
-     */
-    public boolean isResolvedTextDirection() {
-        return (mResolvedTextDirection != TEXT_DIRECTION_UNDEFINED);
-    }
-
-    /**
-     * Reset resolved text direction. Will be resolved during a call to getResolvedLayoutDirection().
+     * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
      */
     protected void resetResolvedTextDirection() {
-        mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+        mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
     }
 
     //
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 1dcbc26..d539a03 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -2634,8 +2634,9 @@
             mInputEventDeliverTimeNanos = System.nanoTime();
         }
 
+        final boolean isTouchEvent = event.isTouchEvent();
         if (mInputEventConsistencyVerifier != null) {
-            if (event.isTouchEvent()) {
+            if (isTouchEvent) {
                 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
             } else {
                 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
@@ -2653,9 +2654,9 @@
             mTranslator.translateEventInScreenToAppWindow(event);
         }
 
-        // Enter touch mode on the down.
-        boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
-        if (isDown) {
+        // Enter touch mode on down or scroll.
+        final int action = event.getAction();
+        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
             ensureTouchMode(true);
         }
 
@@ -2668,8 +2669,10 @@
         }
 
         // Remember the touch position for possible drag-initiation.
-        mLastTouchPoint.x = event.getRawX();
-        mLastTouchPoint.y = event.getRawY();
+        if (isTouchEvent) {
+            mLastTouchPoint.x = event.getRawX();
+            mLastTouchPoint.y = event.getRawY();
+        }
 
         // Dispatch touch to view hierarchy.
         boolean handled = mView.dispatchPointerEvent(event);
@@ -2681,51 +2684,6 @@
             return;
         }
 
-        // Apply edge slop and try again, if appropriate.
-        final int edgeFlags = event.getEdgeFlags();
-        if (edgeFlags != 0 && mView instanceof ViewGroup) {
-            final int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
-            int direction = View.FOCUS_UP;
-            int x = (int)event.getX();
-            int y = (int)event.getY();
-            final int[] deltas = new int[2];
-
-            if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
-                direction = View.FOCUS_DOWN;
-                if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                    deltas[0] = edgeSlop;
-                    x += edgeSlop;
-                } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                    deltas[0] = -edgeSlop;
-                    x -= edgeSlop;
-                }
-            } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
-                direction = View.FOCUS_UP;
-                if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                    deltas[0] = edgeSlop;
-                    x += edgeSlop;
-                } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                    deltas[0] = -edgeSlop;
-                    x -= edgeSlop;
-                }
-            } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                direction = View.FOCUS_RIGHT;
-            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                direction = View.FOCUS_LEFT;
-            }
-
-            View nearest = FocusFinder.getInstance().findNearestTouchable(
-                    ((ViewGroup) mView), x, y, direction, deltas);
-            if (nearest != null) {
-                event.offsetLocation(deltas[0], deltas[1]);
-                event.setEdgeFlags(0);
-                if (mView.dispatchPointerEvent(event)) {
-                    finishMotionEvent(event, sendDone, true);
-                    return;
-                }
-            }
-        }
-
         // Pointer event was unhandled.
         finishMotionEvent(event, sendDone, false);
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 752fd5a..cb3e9c6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -41,6 +41,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.LayoutAnimationController;
 import android.view.animation.Transformation;
+
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 
@@ -5012,37 +5013,6 @@
         }
     }
 
-    /**
-     * This method will be called during text direction resolution (text direction resolution
-     * inheritance)
-     */
-    @Override
-    protected void resolveTextDirection() {
-        int resolvedTextDirection;
-        switch(mTextDirection) {
-            default:
-            case TEXT_DIRECTION_INHERIT:
-                // Try to the text direction from the parent layout
-                if (mParent != null && mParent instanceof ViewGroup) {
-                    resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
-                } else {
-                    // We reached the top of the View hierarchy, so set the text direction
-                    // heuristic to "first strong"
-                    resolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
-                }
-                break;
-            // Pass down the hierarchy the following text direction values
-            case TEXT_DIRECTION_FIRST_STRONG:
-            case TEXT_DIRECTION_ANY_RTL:
-            case TEXT_DIRECTION_CHAR_COUNT:
-            case TEXT_DIRECTION_LTR:
-            case TEXT_DIRECTION_RTL:
-                resolvedTextDirection = mTextDirection;
-                break;
-        }
-        mResolvedTextDirection = resolvedTextDirection;
-    }
-
     @Override
     protected void resetResolvedTextDirection() {
         super.resetResolvedTextDirection();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1449b18..8f8c1d0 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -271,12 +271,6 @@
     Drawable mSelector;
 
     /**
-     * Set to true if we would like to have the selector showing itself.
-     * We still need to draw and position it even if this is false.
-     */
-    boolean mSelectorShowing;
-
-    /**
      * The current position of the selector in the list.
      */
     int mSelectorPosition = INVALID_POSITION;
@@ -1669,7 +1663,6 @@
         setSelectedPositionInt(INVALID_POSITION);
         setNextSelectedPositionInt(INVALID_POSITION);
         mSelectedTop = 0;
-        mSelectorShowing = false;
         mSelectorPosition = INVALID_POSITION;
         mSelectorRect.setEmpty();
         invalidate();
@@ -2025,7 +2018,7 @@
         final boolean isChildViewEnabled = mIsChildViewEnabled;
         if (sel.isEnabled() != isChildViewEnabled) {
             mIsChildViewEnabled = !isChildViewEnabled;
-            if (mSelectorShowing) {
+            if (getSelectedItemPosition() != INVALID_POSITION) {
                 refreshDrawableState();
             }
         }
@@ -2769,6 +2762,7 @@
                 // touch mode). Force an initial layout to get rid of the selection.
                 layoutChildren();
             }
+            updateSelectorState();
         } else {
             int touchMode = mTouchMode;
             if (touchMode == TOUCH_MODE_OVERSCROLL || touchMode == TOUCH_MODE_OVERFLING) {
@@ -2847,14 +2841,6 @@
                         }
                         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                     } else {
-                        if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
-                            // If we couldn't find a view to click on, but the down event
-                            // was touching the edge, we will bail out and try again.
-                            // This allows the edge correcting code in ViewAncestor to try to
-                            // find a nearby view to select
-                            return false;
-                        }
-
                         if (mTouchMode == TOUCH_MODE_FLING) {
                             // Stopped a fling. It is a scroll.
                             createScrollingCache();
@@ -2888,7 +2874,11 @@
         }
 
         case MotionEvent.ACTION_MOVE: {
-            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+            int pointerIndex = ev.findPointerIndex(mActivePointerId);
+            if (pointerIndex == -1) {
+                pointerIndex = 0;
+                mActivePointerId = ev.getPointerId(pointerIndex);
+            }
             final int y = (int) ev.getY(pointerIndex);
             deltaY = y - mMotionY;
             switch (mTouchMode) {
@@ -3464,7 +3454,11 @@
         case MotionEvent.ACTION_MOVE: {
             switch (mTouchMode) {
             case TOUCH_MODE_DOWN:
-                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                if (pointerIndex == -1) {
+                    pointerIndex = 0;
+                    mActivePointerId = ev.getPointerId(pointerIndex);
+                }
                 final int y = (int) ev.getY(pointerIndex);
                 if (startScrollIfNeeded(y - mMotionY)) {
                     return true;
@@ -4521,7 +4515,6 @@
             setSelectedPositionInt(INVALID_POSITION);
             setNextSelectedPositionInt(INVALID_POSITION);
             mSelectedTop = 0;
-            mSelectorShowing = false;
         }
     }
 
@@ -4645,6 +4638,9 @@
                             childrenTop += getVerticalFadingEdgeLength();
                         }
                     }
+                    // Don't ever focus a disabled item.
+                    if (!mAdapter.isEnabled(i)) continue;
+
                     if (top >= childrenTop) {
                         // Found a view whose top is fully visisble
                         selectedPos = firstPosition + i;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 7c9be1e..b428301 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -498,13 +498,6 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-
-        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
-            // Don't handle edge touches immediately -- they may actually belong to one of our
-            // descendants.
-            return false;
-        }
-
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e7a9e41..1f29b16 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3588,17 +3588,6 @@
         return null;
     }
 
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        //noinspection SimplifiableIfStatement
-        if (mItemsCanFocus && ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
-            // Don't handle edge touches immediately -- they may actually belong to one of our
-            // descendants.
-            return false;
-        }
-        return super.onTouchEvent(ev);
-    }
-
     /**
      * Returns the set of checked items ids. The result is only valid if the
      * choice mode has not been set to {@link #CHOICE_MODE_NONE}.
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 4c47d37..867ebb4 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -53,6 +53,10 @@
     // This ensures that we don't stay continually bound to the service and that it can be destroyed
     // if we need the memory elsewhere in the system.
     private static final int sUnbindServiceDelay = 5000;
+
+    // Default height for the default loading view, in case we cannot get inflate the first view
+    private static final int sDefaultLoadingViewHeight = 50;
+
     // Type defs for controlling different messages across the main and worker message queues
     private static final int sDefaultMessageType = 0;
     private static final int sUnbindServiceMessageType = 1;
@@ -386,21 +390,39 @@
 
             // Create a new loading view
             synchronized (mCache) {
+                boolean customLoadingViewAvailable = false;
+
                 if (mUserLoadingView != null) {
-                    // A user-specified loading view
-                    View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
-                    loadingView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(0));
-                    layout.addView(loadingView);
-                } else {
+                    // Try to inflate user-specified loading view
+                    try {
+                        View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
+                        loadingView.setTagInternal(com.android.internal.R.id.rowTypeId,
+                                new Integer(0));
+                        layout.addView(loadingView);
+                        customLoadingViewAvailable = true;
+                    } catch (Exception e) {
+                        Log.w(TAG, "Error inflating custom loading view, using default loading" +
+                                "view instead", e);
+                    }
+                }
+                if (!customLoadingViewAvailable) {
                     // A default loading view
                     // Use the size of the first row as a guide for the size of the loading view
                     if (mFirstViewHeight < 0) {
-                        View firstView = mFirstView.apply(parent.getContext(), parent);
-                        firstView.measure(
-                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-                        mFirstViewHeight = firstView.getMeasuredHeight();
-                        mFirstView = null;
+                        try {
+                            View firstView = mFirstView.apply(parent.getContext(), parent);
+                            firstView.measure(
+                                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+                            mFirstViewHeight = firstView.getMeasuredHeight();
+                            mFirstView = null;
+                        } catch (Exception e) {
+                            float density = mContext.getResources().getDisplayMetrics().density;
+                            mFirstViewHeight = (int)
+                                    Math.round(sDefaultLoadingViewHeight * density);
+                            mFirstView = null;
+                            Log.w(TAG, "Error inflating first RemoteViews" + e);
+                        }
                     }
 
                     // Compose the loading view text
@@ -937,24 +959,40 @@
                 indexMetaData.isRequested = true;
                 int typeId = indexMetaData.typeId;
 
-                // Reuse the convert view where possible
-                if (layout != null) {
-                    if (convertViewTypeId == typeId) {
-                        rv.reapply(context, convertViewChild);
-                        return layout;
+                try {
+                    // Reuse the convert view where possible
+                    if (layout != null) {
+                        if (convertViewTypeId == typeId) {
+                            rv.reapply(context, convertViewChild);
+                            return layout;
+                        }
+                        layout.removeAllViews();
+                    } else {
+                        layout = new RemoteViewsFrameLayout(context);
                     }
-                    layout.removeAllViews();
-                } else {
-                    layout = new RemoteViewsFrameLayout(context);
+
+                    // Otherwise, create a new view to be returned
+                    View newView = rv.apply(context, parent);
+                    newView.setTagInternal(com.android.internal.R.id.rowTypeId,
+                            new Integer(typeId));
+                    layout.addView(newView);
+                    return layout;
+
+                } catch (Exception e){
+                    // We have to make sure that we successfully inflated the RemoteViews, if not
+                    // we return the loading view instead.
+                    Log.w(TAG, "Error inflating RemoteViews at position: " + position + ", using" +
+                            "loading view instead" + e);
+
+                    RemoteViewsFrameLayout loadingView = null;
+                    final RemoteViewsMetaData metaData = mCache.getMetaData();
+                    synchronized (metaData) {
+                        loadingView = metaData.createLoadingView(position, convertView, parent);
+                    }
+                    return loadingView;
+                } finally {
+                    if (hasNewItems) loadNextIndexInBackground();
                 }
-
-                // Otherwise, create a new view to be returned
-                View newView = rv.apply(context, parent);
-                newView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(typeId));
-                layout.addView(newView);
-                if (hasNewItems) loadNextIndexInBackground();
-
-                return layout;
             } else {
                 // If the cache does not have the RemoteViews at this position, then create a
                 // loading view and queue the actual position to be loaded in the background
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 12775a4..e59f731 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -65,7 +65,6 @@
 
     static final float MAX_SCROLL_FACTOR = 0.5f;
 
-
     private long mLastScroll;
 
     private final Rect mTempRect = new Rect();
@@ -506,13 +505,6 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-
-        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
-            // Don't handle edge touches immediately -- they may actually belong to one of our
-            // descendants.
-            return false;
-        }
-
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
         }
@@ -1438,17 +1430,6 @@
 
             final boolean movingDown = velocityY > 0;
 
-            View currentFocused = findFocus();
-            View newFocused =
-                    findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), currentFocused);
-            if (newFocused == null) {
-                newFocused = this;
-            }
-
-            if (newFocused != currentFocused) {
-                    newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP);
-            }
-
             if (mFlingStrictSpan == null) {
                 mFlingStrictSpan = StrictMode.enterCriticalSpan("ScrollView-fling");
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6b4e454..ecbd997 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,11 @@
 
 package android.widget;
 
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
 import android.R;
 import android.content.ClipData;
 import android.content.ClipData.Item;
@@ -59,6 +64,13 @@
 import android.text.Spanned;
 import android.text.SpannedString;
 import android.text.StaticLayout;
+import android.text.TextDirectionHeuristic;
+import android.text.TextDirectionHeuristics;
+import android.text.TextDirectionHeuristics.AnyStrong;
+import android.text.TextDirectionHeuristics.CharCount;
+import android.text.TextDirectionHeuristics.FirstStrong;
+import android.text.TextDirectionHeuristics.TextDirectionAlgorithm;
+import android.text.TextDirectionHeuristics.TextDirectionHeuristicImpl;
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -127,11 +139,6 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.RemoteViews.RemoteView;
 
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.text.BreakIterator;
@@ -5832,6 +5839,7 @@
         if (curs >= 0) {
             mHighlightPathBogus = true;
             makeBlink();
+            bringPointIntoView(curs);
         }
 
         checkForResize();
@@ -5992,14 +6000,17 @@
         Layout.Alignment alignment = getLayoutAlignment();
         boolean shouldEllipsize = mEllipsize != null && mInput == null;
 
+        if (mTextDir == null) {
+            resolveTextDirection();
+        }
         if (mText instanceof Spannable) {
             mLayout = new DynamicLayout(mText, mTransformed, mTextPaint, w,
-                    alignment, mSpacingMult,
+                    alignment, mTextDir, mSpacingMult,
                     mSpacingAdd, mIncludePad, mInput == null ? mEllipsize : null,
                     ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -6036,23 +6047,23 @@
                 } else if (shouldEllipsize) {
                     mLayout = new StaticLayout(mTransformed,
                                 0, mTransformed.length(),
-                                mTextPaint, w, alignment, mSpacingMult,
+                                mTextPaint, w, alignment, mTextDir, mSpacingMult,
                                 mSpacingAdd, mIncludePad, mEllipsize,
                                 ellipsisWidth);
                 } else {
                     mLayout = new StaticLayout(mTransformed, mTextPaint,
-                            w, alignment, mSpacingMult, mSpacingAdd,
+                            w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
                             mIncludePad);
                 }
             } else if (shouldEllipsize) {
                 mLayout = new StaticLayout(mTransformed,
                             0, mTransformed.length(),
-                            mTextPaint, w, alignment, mSpacingMult,
+                            mTextPaint, w, alignment, mTextDir, mSpacingMult,
                             mSpacingAdd, mIncludePad, mEllipsize,
                             ellipsisWidth);
             } else {
                 mLayout = new StaticLayout(mTransformed, mTextPaint,
-                        w, alignment, mSpacingMult, mSpacingAdd,
+                        w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
                         mIncludePad);
             }
         }
@@ -6064,7 +6075,7 @@
             if (shouldEllipsize) hintWidth = w;
 
             if (hintBoring == UNKNOWN_BORING) {
-                hintBoring = BoringLayout.isBoring(mHint, mTextPaint,
+                hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
                                                    mHintBoring);
                 if (hintBoring != null) {
                     mHintBoring = hintBoring;
@@ -6102,23 +6113,23 @@
                 } else if (shouldEllipsize) {
                     mHintLayout = new StaticLayout(mHint,
                                 0, mHint.length(),
-                                mTextPaint, hintWidth, alignment, mSpacingMult,
+                                mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
                                 mSpacingAdd, mIncludePad, mEllipsize,
                                 ellipsisWidth);
                 } else {
                     mHintLayout = new StaticLayout(mHint, mTextPaint,
-                            hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                            hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
                             mIncludePad);
                 }
             } else if (shouldEllipsize) {
                 mHintLayout = new StaticLayout(mHint,
                             0, mHint.length(),
-                            mTextPaint, hintWidth, alignment, mSpacingMult,
+                            mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
                             mSpacingAdd, mIncludePad, mEllipsize,
                             ellipsisWidth);
             } else {
                 mHintLayout = new StaticLayout(mHint, mTextPaint,
-                        hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                        hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
                         mIncludePad);
             }
         }
@@ -6219,6 +6230,10 @@
         BoringLayout.Metrics boring = UNKNOWN_BORING;
         BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
 
+        if (mTextDir == null) {
+            resolveTextDirection();
+        }
+
         int des = -1;
         boolean fromexisting = false;
 
@@ -6231,7 +6246,7 @@
             }
 
             if (des < 0) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -9441,7 +9456,7 @@
         @Override
         public void onClick(View v) {
             if (canPaste()) {
-                paste(getSelectionStart(), getSelectionEnd());
+                onTextContextMenuItem(ID_PASTE);
             }
             hide();
         }
@@ -10439,11 +10454,21 @@
         return mInBatchEditControllers;
     }
 
+    private class TextViewDirectionHeuristic extends TextDirectionHeuristicImpl {
+        private TextViewDirectionHeuristic(TextDirectionAlgorithm algorithm) {
+            super(algorithm);
+        }
+        @Override
+        protected boolean defaultIsRtl() {
+            return getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        }
+    }
+
     /**
      * Resolve the text direction.
      *
      * Text direction of paragraphs in a TextView is determined using a heuristic. If the correct
-     * text direction cannot be determined by the heuristic, the view’s resolved layout direction
+     * text direction cannot be determined by the heuristic, the view's resolved layout direction
      * determines the direction.
      *
      * This heuristic and result is applied individually to each paragraph in a TextView, based on
@@ -10452,157 +10477,27 @@
      */
     @Override
     protected void resolveTextDirection() {
-        int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
-        switch(mTextDirection) {
+        super.resolveTextDirection();
+
+        int textDir = getResolvedTextDirection();
+        switch (textDir) {
             default:
-            case TEXT_DIRECTION_INHERIT:
-                // Try to the text direction from the parent layout. If not possible, then we will
-                // use the default layout direction to decide later
-                if (mParent != null && mParent instanceof ViewGroup) {
-                    resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
-                }
-                break;
             case TEXT_DIRECTION_FIRST_STRONG:
-                resolvedTextDirection = getTextDirectionFromFirstStrong(mText);
+                mTextDir = new TextViewDirectionHeuristic(FirstStrong.INSTANCE);
                 break;
             case TEXT_DIRECTION_ANY_RTL:
-                resolvedTextDirection = getTextDirectionFromAnyRtl(mText);
+                mTextDir = new TextViewDirectionHeuristic(AnyStrong.INSTANCE_RTL);
                 break;
             case TEXT_DIRECTION_CHAR_COUNT:
-                resolvedTextDirection = getTextDirectionFromCharCount(mText);
+                mTextDir = new TextViewDirectionHeuristic(CharCount.INSTANCE_DEFAULT);
                 break;
             case TEXT_DIRECTION_LTR:
-                resolvedTextDirection = TEXT_DIRECTION_LTR;
+                mTextDir = TextDirectionHeuristics.LTR;
                 break;
             case TEXT_DIRECTION_RTL:
-                resolvedTextDirection = TEXT_DIRECTION_RTL;
+                mTextDir = TextDirectionHeuristics.RTL;
                 break;
         }
-        // if we have been so far unable to get the text direction from the heuristics, then we are
-        // falling back using the layout direction
-        if (resolvedTextDirection == TEXT_DIRECTION_UNDEFINED) {
-            switch(getResolvedLayoutDirection()) {
-                default:
-                case LAYOUT_DIRECTION_LTR:
-                    resolvedTextDirection = TEXT_DIRECTION_LTR;
-                    break;
-                case LAYOUT_DIRECTION_RTL:
-                    resolvedTextDirection = TEXT_DIRECTION_RTL;
-                    break;
-            }
-        }
-        mResolvedTextDirection = resolvedTextDirection;
-    }
-
-    /**
-     * Get text direction following the "first strong" heuristic.
-     *
-     * @param cs the CharSequence used to get the text direction.
-     *
-     * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
-     * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
-     */
-    private static int getTextDirectionFromFirstStrong(final CharSequence cs) {
-        final int length = cs.length();
-        if (length == 0) {
-            return TEXT_DIRECTION_UNDEFINED;
-        }
-        for(int i = 0; i < length; i++) {
-            final char c = cs.charAt(i);
-            final byte dir = Character.getDirectionality(c);
-            if (isStrongLtrChar(dir)) {
-                return TEXT_DIRECTION_LTR;
-            } else if (isStrongRtlChar(dir)) {
-                return TEXT_DIRECTION_RTL;
-            }
-        }
-        return TEXT_DIRECTION_UNDEFINED;
-    }
-
-    /**
-     * Get text direction following the "any RTL" heuristic.
-     *
-     * @param cs the CharSequence used to get the text direction.
-     *
-     * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
-     * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
-     */
-    private static int getTextDirectionFromAnyRtl(final CharSequence cs) {
-        final int length = cs.length();
-        if (length == 0) {
-            return TEXT_DIRECTION_UNDEFINED;
-        }
-        boolean foundStrongLtr = false;
-        boolean foundStrongRtl = false;
-        for(int i = 0; i < length; i++) {
-            final char c = cs.charAt(i);
-            final byte dir = Character.getDirectionality(c);
-            if (isStrongLtrChar(dir)) {
-                foundStrongLtr = true;
-            } else if (isStrongRtlChar(dir)) {
-                foundStrongRtl = true;
-                break;
-            }
-        }
-        if (foundStrongRtl) {
-            return TEXT_DIRECTION_RTL;
-        }
-        if (foundStrongLtr) {
-            return TEXT_DIRECTION_LTR;
-        }
-        return TEXT_DIRECTION_UNDEFINED;
-    }
-
-    /**
-     * Get text direction following the "char count" heuristic.
-     *
-     * @param cs the CharSequence used to get the text direction.
-     *
-     * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
-     * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
-     */
-    private int getTextDirectionFromCharCount(CharSequence cs) {
-        final int length = cs.length();
-        if (length == 0) {
-            return TEXT_DIRECTION_UNDEFINED;
-        }
-        int countLtr = 0;
-        int countRtl = 0;
-        for(int i = 0; i < length; i++) {
-            final char c = cs.charAt(i);
-            final byte dir = Character.getDirectionality(c);
-            if (isStrongLtrChar(dir)) {
-                countLtr++;
-            } else if (isStrongRtlChar(dir)) {
-                countRtl++;
-            }
-        }
-        final float percentLtr = ((float) countLtr) / (countLtr + countRtl);
-        if (percentLtr > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) {
-            return TEXT_DIRECTION_LTR;
-        }
-        final float percentRtl = ((float) countRtl) / (countLtr + countRtl);
-        if (percentRtl > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) {
-            return TEXT_DIRECTION_RTL;
-        }
-        return TEXT_DIRECTION_UNDEFINED;
-    }
-
-    /**
-     * Return true if the char direction is corresponding to a "strong RTL char" following the
-     * Unicode Bidirectional Algorithm (UBA).
-     */
-    private static boolean isStrongRtlChar(final byte dir) {
-        return (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
-                dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC);
-    }
-
-    /**
-     * Return true if the char direction is corresponding to a "strong LTR char" following the
-     * Unicode Bidirectional Algorithm (UBA).
-     */
-    private static boolean isStrongLtrChar(final byte dir) {
-        return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
     }
 
     /**
@@ -10768,6 +10663,8 @@
 
     private BoringLayout mSavedLayout, mSavedHintLayout;
 
+    private TextDirectionHeuristic mTextDir = null;
+
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
     private InputFilter[] mFilters = NO_FILTERS;
     private static final Spanned EMPTY_SPANNED = new SpannedString("");
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 243c605..cf5666c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -500,7 +500,7 @@
 
     @Override
     public int getHeight() {
-        return mActionView.getHeight();
+        return mContainerView.getHeight();
     }
 
     @Override
diff --git a/services/java/com/android/server/ProcessStats.java b/core/java/com/android/internal/os/ProcessStats.java
similarity index 99%
rename from services/java/com/android/server/ProcessStats.java
rename to core/java/com/android/internal/os/ProcessStats.java
index f693ed1..ea5ce09 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/core/java/com/android/internal/os/ProcessStats.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.internal.os;
 
 import static android.os.Process.*;
 
@@ -182,7 +182,7 @@
 
         public String baseName;
         public String name;
-        int nameWidth;
+        public int nameWidth;
 
         public long base_uptime;
         public long rel_uptime;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 49eaf19..0397dfa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1489,9 +1489,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <service android:name="com.android.server.LoadAverageService"
-                android:exported="true" />
-
         <service android:name="com.android.internal.service.wallpaper.ImageWallpaper"
                 android:permission="android.permission.BIND_WALLPAPER">
         </service>
diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml
index a885211..27dd9b8 100644
--- a/core/res/res/layout/list_menu_item_icon.xml
+++ b/core/res/res/layout/list_menu_item_icon.xml
@@ -21,6 +21,8 @@
     android:layout_gravity="center_vertical"
     android:layout_marginLeft="8dip"
     android:layout_marginRight="-8dip"
-    android:scaleType="center"
+    android:layout_marginTop="8dip"
+    android:layout_marginBottom="8dip"
+    android:scaleType="centerInside"
     android:duplicateParentState="true" />
 
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index fb898ee..4e7981a 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -44,8 +44,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="0px"
                 android:layout_weight="1"
-                android:paddingTop="16dp"
-                android:paddingBottom="16dp"
+                android:paddingTop="@dimen/preference_screen_header_vertical_padding"
+                android:paddingBottom="@dimen/preference_screen_header_vertical_padding"
                 android:drawSelectorOnTop="false"
                 android:cacheColorHint="@android:color/transparent"
                 android:listPreferredItemHeight="48dp"
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 9ffe6b1..17bf561 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -44,5 +44,7 @@
     <!-- Size of status line font in LockScreen. -->
     <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
 
+    <!-- Preference activity, vertical padding for the header list -->
+    <dimen name="reference_screen_header_vertical_padding">16dp</dimen>
 </resources>
 
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 0f04a67..bcf1991 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,6 +22,15 @@
     <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
+       <item>@drawable/spinner_black_16</item>
+       <item>@drawable/spinner_black_20</item>
+       <item>@drawable/spinner_black_48</item>
+       <item>@drawable/spinner_black_76</item>
+       <item>@drawable/spinner_white_16</item>
+       <item>@drawable/spinner_white_48</item>
+       <item>@drawable/spinner_white_76</item>
+       <item>@drawable/toast_frame</item>
+       <item>@drawable/toast_frame_holo</item>
        <item>@drawable/btn_check_on_selected</item>
        <item>@drawable/btn_check_on_pressed_holo_light</item>
        <item>@drawable/btn_check_on_pressed_holo_dark</item>
@@ -109,6 +118,11 @@
        <item>@drawable/btn_default_disabled_holo_dark</item>
        <item>@drawable/btn_default_disabled_focused_holo_light</item>
        <item>@drawable/btn_default_disabled_focused_holo_dark</item>
+       <item>@drawable/btn_dropdown_disabled</item>
+       <item>@drawable/btn_dropdown_disabled_focused</item>
+       <item>@drawable/btn_dropdown_normal</item>
+       <item>@drawable/btn_dropdown_pressed</item>
+       <item>@drawable/btn_dropdown_selected</item>
        <item>@drawable/btn_toggle_on_pressed_holo_light</item>
        <item>@drawable/btn_toggle_on_pressed_holo_dark</item>
        <item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -141,6 +155,10 @@
        <item>@drawable/edit_text_holo_light</item>
        <item>@drawable/edit_text_holo_dark</item>
        <item>@drawable/edit_text</item>
+       <item>@drawable/expander_close_holo_dark</item>
+       <item>@drawable/expander_close_holo_light</item>
+       <item>@drawable/expander_ic_maximized</item>
+       <item>@drawable/expander_ic_minimized</item>
        <item>@drawable/expander_group</item>
        <item>@drawable/expander_group_holo_dark</item>
        <item>@drawable/expander_group_holo_light</item>
@@ -157,6 +175,8 @@
        <item>@drawable/menu_background_fill_parent_width</item>
        <item>@drawable/menu_submenu_background</item>
        <item>@drawable/menu_selector</item>
+       <item>@drawable/overscroll_edge</item>
+       <item>@drawable/overscroll_glow</item>
        <item>@drawable/panel_background</item>
        <item>@drawable/popup_bottom_bright</item>
        <item>@drawable/popup_bottom_dark</item>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0f6e5cf..abc56ec 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -96,6 +96,8 @@
          is along the major axis (that is the screen is landscape).  This may
          be either a fraction or a dimension. -->
     <item type="dimen" name="dialog_min_width_major">65%</item>
+    <!-- Preference activity, vertical padding for the header list -->
+    <dimen name="preference_screen_header_vertical_padding">0dp</dimen>
 
     <!-- The platform's desired minimum size for a dialog's width when it
          is along the minor axis (that is the screen is portrait).  This may
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a5cd6e3..6b75146 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1672,6 +1672,7 @@
 
     <style name="Widget.Holo.ProgressBar.Small" parent="Widget.ProgressBar.Small">
         <item name="android:indeterminateDrawable">@android:drawable/progress_small_holo</item>
+        <item name="android:animationResolution">33</item>
     </style>
 
     <style name="Widget.Holo.ProgressBar.Small.Title">
@@ -1679,6 +1680,7 @@
 
     <style name="Widget.Holo.ProgressBar.Large" parent="Widget.ProgressBar.Large">
         <item name="android:indeterminateDrawable">@android:drawable/progress_large_holo</item>
+        <item name="android:animationResolution">33</item>
     </style>
 
     <style name="Widget.Holo.ProgressBar.Inverse">
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index c54e4a1..7dc95db 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,13 +16,13 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.GetChars;
 import android.view.View;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * TextViewTest tests {@link TextView}.
  */
@@ -240,12 +240,12 @@
 
         getActivity().runOnUiThread(new Runnable() {
             public void run() {
-                tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+                ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+                tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
                 assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
-                assertEquals(true, tv.isResolvedTextDirection());
 
                 ll.removeView(tv);
-                assertEquals(false, tv.isResolvedTextDirection());
+                assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getResolvedTextDirection());
             }
         });
     }
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index e705c6f..5b5b731 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -104,6 +104,24 @@
     // queued buffers will be retired in order.
     // The default mode is asynchronous.
     virtual status_t setSynchronousMode(bool enabled) = 0;
+
+    // connect attempts to connect a client API to the SurfaceTexture.  This
+    // must be called before any other ISurfaceTexture methods are called except
+    // for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // SurfaceTexture and no corresponding disconnect call was made.
+    virtual status_t connect(int api) = 0;
+
+    // disconnect attempts to disconnect a client API from the SurfaceTexture.
+    // Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the SurfaceTexture is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index e36360c..4080f27 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -44,6 +44,7 @@
         MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
     };
     enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
 
     struct FrameAvailableListener : public virtual RefBase {
         // onFrameAvailable() is called from queueBuffer() each time an
@@ -97,6 +98,24 @@
     // The default mode is asynchronous.
     virtual status_t setSynchronousMode(bool enabled);
 
+    // connect attempts to connect a client API to the SurfaceTexture.  This
+    // must be called before any other ISurfaceTexture methods are called except
+    // for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // SurfaceTexture and no corresponding disconnect call was made.
+    virtual status_t connect(int api);
+
+    // disconnect attempts to disconnect a client API from the SurfaceTexture.
+    // Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the SurfaceTexture is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api);
+
     // updateTexImage sets the image contents of the target texture to that of
     // the most recently queued buffer.
     //
@@ -362,6 +381,11 @@
     // mAllowSynchronousMode whether we allow synchronous mode or not
     const bool mAllowSynchronousMode;
 
+    // mConnectedApi indicates the API that is currently connected to this
+    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
     // mDequeueCondition condition used for dequeueBuffer in synchronous mode
     mutable Condition mDequeueCondition;
 
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 9db7364..5ec469e 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -129,9 +129,6 @@
     // a timestamp is auto-generated when queueBuffer is called.
     int64_t mTimestamp;
 
-    // mConnectedApi holds the currently connected API to this surface
-    int mConnectedApi;
-
     // mQueryWidth is the width returned by query(). It is set to width
     // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
     uint32_t mQueryWidth;
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 23ffd59..f38f6ce 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -23,8 +23,8 @@
  */
 interface IKeyChainService {
     // APIs used by KeyChain
-    byte[] getPrivateKey(String alias, String authToken);
-    byte[] getCertificate(String alias, String authToken);
+    byte[] getPrivateKey(String alias);
+    byte[] getCertificate(String alias);
 
     // APIs used by CertInstaller
     void installCaCertificate(in byte[] caCertificate);
@@ -32,4 +32,8 @@
     // APIs used by Settings
     boolean deleteCaCertificate(String alias);
     boolean reset();
+
+    // APIs used by KeyChainActivity
+    void setGrant(int uid, String alias, boolean value);
+    boolean hasGrant(int uid, String alias);
 }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 6229331..db6388a 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,36 +15,25 @@
  */
 package android.security;
 
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.IOException;
-import java.security.KeyFactory;
 import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
@@ -266,7 +255,7 @@
             throw new NullPointerException("response == null");
         }
         Intent intent = new Intent(ACTION_CHOOSER);
-        intent.putExtra(EXTRA_RESPONSE, new AliasResponse(activity, response));
+        intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
         intent.putExtra(EXTRA_HOST, host);
         intent.putExtra(EXTRA_PORT, port);
         intent.putExtra(EXTRA_ALIAS, alias);
@@ -276,56 +265,12 @@
     }
 
     private static class AliasResponse extends IKeyChainAliasCallback.Stub {
-        private final Activity activity;
         private final KeyChainAliasCallback keyChainAliasResponse;
-        private AliasResponse(Activity activity, KeyChainAliasCallback keyChainAliasResponse) {
-            this.activity = activity;
+        private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) {
             this.keyChainAliasResponse = keyChainAliasResponse;
         }
         @Override public void alias(String alias) {
-            if (alias == null) {
-                keyChainAliasResponse.alias(null);
-                return;
-            }
-            AccountManager accountManager = AccountManager.get(activity);
-            accountManager.getAuthToken(getAccount(activity),
-                                        alias,
-                                        null,
-                                        activity,
-                                        new AliasAccountManagerCallback(keyChainAliasResponse,
-                                                                        alias),
-                                        null);
-        }
-    }
-
-    private static class AliasAccountManagerCallback implements AccountManagerCallback<Bundle> {
-        private final KeyChainAliasCallback keyChainAliasResponse;
-        private final String alias;
-        private AliasAccountManagerCallback(KeyChainAliasCallback keyChainAliasResponse,
-                                            String alias) {
-            this.keyChainAliasResponse = keyChainAliasResponse;
-            this.alias = alias;
-        }
-        @Override public void run(AccountManagerFuture<Bundle> future) {
-            Bundle bundle;
-            try {
-                bundle = future.getResult();
-            } catch (OperationCanceledException e) {
-                keyChainAliasResponse.alias(null);
-                return;
-            } catch (IOException e) {
-                keyChainAliasResponse.alias(null);
-                return;
-            } catch (AuthenticatorException e) {
-                keyChainAliasResponse.alias(null);
-                return;
-            }
-            String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
-            if (authToken != null) {
-                keyChainAliasResponse.alias(alias);
-            } else {
-                keyChainAliasResponse.alias(null);
-            }
+            keyChainAliasResponse.alias(alias);
         }
     }
 
@@ -347,12 +292,8 @@
         }
         KeyChainConnection keyChainConnection = bind(context);
         try {
-            String authToken = authToken(context, alias);
-            if (authToken == null) {
-                return null;
-            }
             IKeyChainService keyChainService = keyChainConnection.getService();
-            byte[] privateKeyBytes = keyChainService.getPrivateKey(alias, authToken);
+            byte[] privateKeyBytes = keyChainService.getPrivateKey(alias);
             return toPrivateKey(privateKeyBytes);
         } catch (RemoteException e) {
             throw new KeyChainException(e);
@@ -382,12 +323,8 @@
         }
         KeyChainConnection keyChainConnection = bind(context);
         try {
-            String authToken = authToken(context, alias);
-            if (authToken == null) {
-                return null;
-            }
             IKeyChainService keyChainService = keyChainConnection.getService();
-            byte[] certificateBytes = keyChainService.getCertificate(alias, authToken);
+            byte[] certificateBytes = keyChainService.getCertificate(alias);
             List<X509Certificate> chain = new ArrayList<X509Certificate>();
             chain.add(toCertificate(certificateBytes));
             TrustedCertificateStore store = new TrustedCertificateStore();
@@ -438,50 +375,6 @@
         }
     }
 
-    private static String authToken(Context context, String alias) {
-        AccountManager accountManager = AccountManager.get(context);
-        AccountManagerFuture<Bundle> future = accountManager.getAuthToken(getAccount(context),
-                                                                          alias,
-                                                                          false,
-                                                                          null,
-                                                                          null);
-        Bundle bundle;
-        try {
-            bundle = future.getResult();
-        } catch (OperationCanceledException e) {
-            throw new AssertionError(e);
-        } catch (IOException e) {
-            // KeyChainAccountAuthenticator doesn't do I/O
-            throw new AssertionError(e);
-        } catch (AuthenticatorException e) {
-            throw new AssertionError(e);
-        }
-        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
-        if (intent != null) {
-            return null;
-        }
-        String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
-        if (authToken == null) {
-            throw new AssertionError("Invalid authtoken");
-        }
-        return authToken;
-    }
-
-    private static Account getAccount(Context context) {
-        AccountManager accountManager = AccountManager.get(context);
-        Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
-        if (accounts.length == 0) {
-            try {
-                // Account is created if necessary during binding of the IKeyChainService
-                bind(context).close();
-            } catch (InterruptedException e) {
-                throw new AssertionError(e);
-            }
-            accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
-        }
-        return accounts[0];
-    }
-
     /**
      * @hide for reuse by CertInstaller and Settings.
      * @see KeyChain#bind
@@ -517,11 +410,15 @@
         ensureNotOnMainThread(context);
         final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
         ServiceConnection keyChainServiceConnection = new ServiceConnection() {
+            volatile boolean mConnectedAtLeastOnce = false;
             @Override public void onServiceConnected(ComponentName name, IBinder service) {
-                try {
-                    q.put(IKeyChainService.Stub.asInterface(service));
-                } catch (InterruptedException e) {
-                    throw new AssertionError(e);
+                if (!mConnectedAtLeastOnce) {
+                    mConnectedAtLeastOnce = true;
+                    try {
+                        q.put(IKeyChainService.Stub.asInterface(service));
+                    } catch (InterruptedException e) {
+                        // will never happen, since the queue starts with one available slot
+                    }
                 }
             }
             @Override public void onServiceDisconnected(ComponentName name) {}
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 16e3780..41434a4 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -41,6 +41,8 @@
     GET_ALLOCATOR,
     QUERY,
     SET_SYNCHRONOUS_MODE,
+    CONNECT,
+    DISCONNECT,
 };
 
 
@@ -154,7 +156,23 @@
         return result;
     }
 
+    virtual status_t connect(int api) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(api);
+        remote()->transact(CONNECT, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
 
+    virtual status_t disconnect(int api) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(api);
+        remote()->transact(DISCONNECT, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
@@ -248,6 +266,20 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+        case CONNECT: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int api = data.readInt32();
+            status_t res = connect(api);
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
+        case DISCONNECT: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int api = data.readInt32();
+            status_t res = disconnect(api);
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 886a3fb..1410481 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -92,7 +92,8 @@
     mNextTransform(0),
     mTexName(tex),
     mSynchronousMode(false),
-    mAllowSynchronousMode(allowSynchronousMode) {
+    mAllowSynchronousMode(allowSynchronousMode),
+    mConnectedApi(NO_CONNECTED_API) {
     LOGV("SurfaceTexture::SurfaceTexture");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -493,6 +494,50 @@
     return OK;
 }
 
+status_t SurfaceTexture::connect(int api) {
+    LOGV("SurfaceTexture::connect");
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi != NO_CONNECTED_API) {
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t SurfaceTexture::disconnect(int api) {
+    LOGV("SurfaceTexture::disconnect");
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi == api) {
+                mConnectedApi = NO_CONNECTED_API;
+            } else {
+                err = -EINVAL;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
 status_t SurfaceTexture::updateTexImage() {
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index e203035..f39cabf 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -27,7 +27,7 @@
         const sp<ISurfaceTexture>& surfaceTexture):
         mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
         mReqHeight(0), mReqFormat(0), mReqUsage(0),
-        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
+        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
         mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
         mMutex() {
     // Initialize the ANativeWindow function pointers.
@@ -327,45 +327,22 @@
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnectedApi) {
-                err = -EINVAL;
-            } else {
-                mConnectedApi = api;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
+    return mSurfaceTexture->connect(api);
 }
 
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnectedApi == api) {
-                mConnectedApi = 0;
-            } else {
-                err = -EINVAL;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
+    return mSurfaceTexture->disconnect(api);
 }
 
 int SurfaceTextureClient::getConnectedApi() const
 {
+    // XXX: This method will be going away shortly, and is currently bogus.  It
+    // always returns "nothing is connected".  It will go away once Surface gets
+    // updated to actually connect as the 'CPU' API when locking a buffer.
     Mutex::Autolock lock(mMutex);
-    return mConnectedApi;
+    return 0;
 }
 
 
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 8798612..447a7ff 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -340,10 +340,6 @@
 Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) {
     Context * rsc = new Context();
 
-    // Temporary to avoid breaking the tools
-    if (!dev) {
-        return rsc;
-    }
     if (!rsc->initContext(dev, sc)) {
         delete rsc;
         return NULL;
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 70b7278..7023a1f 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -21,14 +21,16 @@
 using namespace android;
 using namespace android::renderscript;
 
-LocklessCommandFifo::LocklessCommandFifo() {
+LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0) {
 }
 
 LocklessCommandFifo::~LocklessCommandFifo() {
     if (!mInShutdown) {
         shutdown();
     }
-    free(mBuffer);
+    if (mBuffer) {
+        free(mBuffer);
+    }
 }
 
 void LocklessCommandFifo::shutdown() {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index ab164c3..1c8b89c 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -21,8 +21,7 @@
 using namespace android;
 using namespace android::renderscript;
 
-ThreadIO::ThreadIO() {
-    mToCore.init(16 * 1024);
+ThreadIO::ThreadIO() : mUsingSocket(false) {
 }
 
 ThreadIO::~ThreadIO() {
@@ -30,6 +29,7 @@
 
 void ThreadIO::init(bool useSocket) {
     mUsingSocket = useSocket;
+    mToCore.init(16 * 1024);
 
     if (mUsingSocket) {
         mToClientSocket.init();
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 50312e7..d18c0a2 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -161,6 +161,7 @@
     pthread_t thread;
     int result = pthread_create(&thread, &attr,
                     (android_pthread_entry)entryFunction, userData);
+    pthread_attr_destroy(&attr);
     if (result != 0) {
         LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
              "(android threadPriority=%d)",
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 87ae3d5..bfb37a6 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -252,13 +252,15 @@
         "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
 
     void* item = editItemLocation(index);
-    if (item == 0)
-        return NO_MEMORY;
-    _do_destroy(item, 1);
-    if (prototype == 0) {
-        _do_construct(item, 1);
-    } else {
-        _do_copy(item, prototype, 1);
+    if (item != prototype) {
+        if (item == 0)
+            return NO_MEMORY;
+        _do_destroy(item, 1);
+        if (prototype == 0) {
+            _do_construct(item, 1);
+        } else {
+            _do_copy(item, prototype, 1);
+        }
     }
     return ssize_t(index);
 }
@@ -347,9 +349,10 @@
 //    LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    if (where > mCount)
-        where = mCount;
-      
+    LOG_ASSERT(where <= mCount,
+            "[%p] _grow: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
+
     const size_t new_size = mCount + amount;
     if (capacity() < new_size) {
         const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
@@ -366,10 +369,10 @@
             SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
             if (sb) {
                 void* array = sb->data();
-                if (where>0) {
+                if (where != 0) {
                     _do_copy(array, mStorage, where);
                 }
-                if (mCount>where) {
+                if (where != mCount) {
                     const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
                     void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
                     _do_copy(dest, from, mCount-where);
@@ -379,15 +382,14 @@
             }
         }
     } else {
-        ssize_t s = mCount-where;
-        if (s>0) {
-            void* array = editArrayImpl();    
-            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+        if (where != mCount) {
+            void* array = editArrayImpl();
             const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
-            _do_move_forward(to, from, s);
+            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            _do_move_forward(to, from, mCount - where);
         }
     }
-    mCount += amount;
+    mCount = new_size;
     void* free_space = const_cast<void*>(itemLocation(where));
     return free_space;
 }
@@ -400,14 +402,15 @@
 //    LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    if (where >= mCount)
-        where = mCount - amount;
+    LOG_ASSERT(where + amount <= mCount,
+            "[%p] _shrink: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
 
     const size_t new_size = mCount - amount;
     if (new_size*3 < capacity()) {
         const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
 //        LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
-        if ((where == mCount-amount) &&
+        if ((where == new_size) &&
             (mFlags & HAS_TRIVIAL_COPY) &&
             (mFlags & HAS_TRIVIAL_DTOR))
         {
@@ -418,31 +421,28 @@
             SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
             if (sb) {
                 void* array = sb->data();
-                if (where>0) {
+                if (where != 0) {
                     _do_copy(array, mStorage, where);
                 }
-                if (mCount > where+amount) {
+                if (where != new_size) {
                     const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
                     void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
-                    _do_copy(dest, from, mCount-(where+amount));
+                    _do_copy(dest, from, new_size - where);
                 }
                 release_storage();
                 mStorage = const_cast<void*>(array);
             }
         }
     } else {
-        void* array = editArrayImpl();    
+        void* array = editArrayImpl();
         void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
         _do_destroy(to, amount);
-        ssize_t s = mCount-(where+amount);
-        if (s>0) {
+        if (where != new_size) {
             const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
-            _do_move_backward(to, from, s);
+            _do_move_backward(to, from, new_size - where);
         }
     }
-
-    // adjust the number of items...
-    mCount -= amount;
+    mCount = new_size;
 }
 
 size_t VectorImpl::itemSize() const {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index e89be08..8c8569a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -707,7 +707,9 @@
             map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
             map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm);
 
-            if (!mNoMedia) {
+            if (mNoMedia) {
+                map.put(MediaStore.MediaColumns.NO_MEDIA, true);
+            } else {
                 if (MediaFile.isVideoFileType(mFileType)) {
                     map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0
                             ? mArtist : MediaStore.UNKNOWN_STRING));
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 788464e..0098537 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -453,7 +453,6 @@
 }
 
 void AwesomePlayer::reset() {
-    LOGI("reset");
     Mutex::Autolock autoLock(mLock);
     reset_l();
 }
@@ -467,10 +466,8 @@
                     Playback::STOP, 0);
             mDecryptHandle = NULL;
             mDrmManagerClient = NULL;
-            LOGI("DRM manager client stopped");
     }
 
-
     if (mFlags & PLAYING) {
         uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
         if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
@@ -503,7 +500,6 @@
         mPreparedCondition.wait(mLock);
     }
 
-    LOGI("cancel player events");
     cancelPlayerEvents();
 
     mWVMExtractor.clear();
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index b7b0dc0f..5cab60e 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3539,7 +3539,7 @@
 }
 
 status_t OMXCodec::stop() {
-    CODEC_LOGI("stop mState=%d", mState);
+    CODEC_LOGV("stop mState=%d", mState);
 
     Mutex::Autolock autoLock(mLock);
 
@@ -3601,7 +3601,6 @@
         mLeftOverBuffer = NULL;
     }
 
-    CODEC_LOGI("stopping video source");
     mSource->stop();
 
     CODEC_LOGI("stopped in state %d", mState);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 25f30d6..bc24dbb 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -96,9 +96,14 @@
         mQueueChanged.signal();
     }
 
-    // Don't call join on myself
+    // A join on self can happen if the last ref to CallbackDispatcher
+    // is released within the CallbackDispatcherThread loop
     status_t status = mThread->join();
-    CHECK(status == NO_ERROR);
+    if (status != WOULD_BLOCK) {
+        // Other than join to self, the only other error return codes are
+        // whatever readyToRun() returns, and we don't override that
+        CHECK_EQ(status, NO_ERROR);
+    }
 }
 
 void OMX::CallbackDispatcher::post(const omx_message &msg) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 26ea225..d32df6e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -30,6 +30,15 @@
         <service android:name=".screenshot.TakeScreenshotService"
             android:exported="false" />
 
+        <service android:name=".LoadAverageService"
+                android:exported="true" />
+
+        <receiver android:name=".BootReceiver" >
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
+
         <activity android:name=".usb.UsbStorageActivity"
                 android:excludeFromRecents="true">
         </activity>
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
new file mode 100644
index 0000000..de005aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.Slog;
+
+/**
+ * Performs a number of miscellaneous, non-system-critical actions
+ * after the system has finished booting.
+ */
+public class BootReceiver extends BroadcastReceiver {
+    private static final String TAG = "SystemUIBootReceiver";
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        try {
+            // Start the load average overlay, if activated
+            ContentResolver res = context.getContentResolver();
+            if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
+                Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
+                context.startService(loadavg);
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Can't start load average service", e);
+        }
+    }
+}
diff --git a/services/java/com/android/server/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
similarity index 98%
rename from services/java/com/android/server/LoadAverageService.java
rename to packages/SystemUI/src/com/android/systemui/LoadAverageService.java
index e05b570..67dc3cd 100644
--- a/services/java/com/android/server/LoadAverageService.java
+++ b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.systemui;
+
+import com.android.internal.os.ProcessStats;
 
 import android.app.Service;
 import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 75e799c..e177565 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -75,6 +75,7 @@
 
     private StatusView mStatusView;
     private final boolean mUseSystemIME = true; // TODO: Make configurable
+    private boolean mResuming; // used to prevent poking the wakelock during onResume()
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
     // any passwords with length less than or equal to this length.
@@ -185,7 +186,9 @@
             }
 
             public void afterTextChanged(Editable s) {
-                mCallback.pokeWakelock();
+                if (!mResuming) {
+                    mCallback.pokeWakelock();
+                }
             }
         });
     }
@@ -208,6 +211,7 @@
 
     /** {@inheritDoc} */
     public void onResume() {
+        mResuming = true;
         // reset status
         mStatusView.resetStatusInfo(mUpdateMonitor, mLockPatternUtils);
 
@@ -222,6 +226,7 @@
         if (deadline != 0) {
             handleAttemptLockout(deadline);
         }
+        mResuming = false;
     }
 
     /** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index dff0556..4be00c5 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2240,7 +2240,7 @@
             }
 
             PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-            if (st != null && st.menu != null) {
+            if (st != null && st.menu != null && mFeatureId < 0) {
                 st.menu.close();
             }
         }
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 49cb864..b2fbcb1 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -181,25 +181,6 @@
                     | AMOTION_EVENT_BUTTON_TERTIARY);
 }
 
-static int32_t calculateEdgeFlagsUsingPointerBounds(
-        const sp<PointerControllerInterface>& pointerController, float x, float y) {
-    int32_t edgeFlags = 0;
-    float minX, minY, maxX, maxY;
-    if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-        if (x <= minX) {
-            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
-        } else if (x >= maxX) {
-            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
-        }
-        if (y <= minY) {
-            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
-        } else if (y >= maxY) {
-            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
-        }
-    }
-    return edgeFlags;
-}
-
 static float calculateCommonVector(float a, float b) {
     if (a > 0 && b > 0) {
         return a < b ? a : b;
@@ -1619,7 +1600,6 @@
     }
 
     int32_t motionEventAction;
-    int32_t motionEventEdgeFlags;
     int32_t lastButtonState, currentButtonState;
     PointerProperties pointerProperties;
     PointerCoords pointerCoords;
@@ -1697,8 +1677,6 @@
             }
         }
 
-        motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
-
         pointerProperties.clear();
         pointerProperties.id = 0;
         pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
@@ -1742,11 +1720,6 @@
             mPointerController->getPosition(&x, &y);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-
-            if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-                motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds(
-                        mPointerController, x, y);
-            }
         } else {
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -1771,7 +1744,7 @@
     // Send motion event.
     int32_t metaState = mContext->getGlobalMetaState();
     getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
-            motionEventAction, 0, metaState, currentButtonState, motionEventEdgeFlags,
+            motionEventAction, 0, metaState, currentButtonState, 0,
             1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
 
     // Send hover move after UP to tell the application that the mouse is hovering now.
@@ -3168,9 +3141,8 @@
     }
 
     // Update current touch coordinates.
-    int32_t edgeFlags;
     float xPrecision, yPrecision;
-    prepareTouches(&edgeFlags, &xPrecision, &yPrecision);
+    prepareTouches(&xPrecision, &yPrecision);
 
     // Dispatch motions.
     BitSet32 currentIdBits = mCurrentTouch.idBits;
@@ -3239,13 +3211,10 @@
             if (dispatchedIdBits.count() == 1) {
                 // First pointer is going down.  Set down time.
                 mDownTime = when;
-            } else {
-                // Only send edge flags with first pointer down.
-                edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
             }
 
             dispatchMotion(when, policyFlags, mTouchSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags,
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
                     mCurrentTouchProperties, mCurrentTouchCoords,
                     mCurrentTouch.idToIndex, dispatchedIdBits, downId,
                     xPrecision, yPrecision, mDownTime);
@@ -3259,8 +3228,7 @@
     }
 }
 
-void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
-        float* outXPrecision, float* outYPrecision) {
+void TouchInputMapper::prepareTouches(float* outXPrecision, float* outYPrecision) {
     uint32_t currentPointerCount = mCurrentTouch.pointerCount;
     uint32_t lastPointerCount = mLastTouch.pointerCount;
 
@@ -3471,28 +3439,6 @@
         properties.toolType = getTouchToolType(mCurrentTouch.pointers[i].isStylus);
     }
 
-    // Check edge flags by looking only at the first pointer since the flags are
-    // global to the event.
-    *outEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
-    if (lastPointerCount == 0 && currentPointerCount > 0) {
-        const PointerData& in = mCurrentTouch.pointers[0];
-
-        if (in.x <= mRawAxes.x.minValue) {
-            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
-                    mLocked.surfaceOrientation);
-        } else if (in.x >= mRawAxes.x.maxValue) {
-            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
-                    mLocked.surfaceOrientation);
-        }
-        if (in.y <= mRawAxes.y.minValue) {
-            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
-                    mLocked.surfaceOrientation);
-        } else if (in.y >= mRawAxes.y.maxValue) {
-            *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
-                    mLocked.surfaceOrientation);
-        }
-    }
-
     *outXPrecision = mLocked.orientedXPrecision;
     *outYPrecision = mLocked.orientedYPrecision;
 }
@@ -3640,19 +3586,12 @@
             downGestureIdBits.clearBit(id);
             dispatchedGestureIdBits.markBit(id);
 
-            int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
             if (dispatchedGestureIdBits.count() == 1) {
-                // First pointer is going down.  Calculate edge flags and set down time.
-                uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
-                const PointerCoords& downCoords = mPointerGesture.currentGestureCoords[index];
-                edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
-                        downCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
-                        downCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
                 mPointerGesture.downTime = when;
             }
 
             dispatchMotion(when, policyFlags, mPointerSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags,
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
                     mPointerGesture.currentGestureProperties,
                     mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                     dispatchedGestureIdBits, id,
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 69fa6b4..b1fdcf2 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -1176,7 +1176,7 @@
 
     TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouches(nsecs_t when, uint32_t policyFlags);
-    void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
+    void prepareTouches(float* outXPrecision, float* outYPrecision);
     void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
     bool preparePointerGestures(nsecs_t when,
             bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout);
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index b9ff8d0..6665614 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -28,7 +27,6 @@
 import android.os.FileUtils;
 import android.os.RecoverySystem;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.util.Slog;
 
 import java.io.File;
@@ -59,17 +57,6 @@
 
     @Override
     public void onReceive(final Context context, Intent intent) {
-        try {
-            // Start the load average overlay, if activated
-            ContentResolver res = context.getContentResolver();
-            if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
-                Intent loadavg = new Intent(context, com.android.server.LoadAverageService.class);
-                context.startService(loadavg);
-            }
-        } catch (Exception e) {
-            Slog.e(TAG, "Can't start load average service", e);
-        }
-
         // Log boot events in the background to avoid blocking the main thread with I/O
         new Thread() {
             @Override
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 85891a2..55c92e8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,7 +35,7 @@
 import android.net.INetworkPolicyManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.LinkProperties.CompareAddressesResult;
+import android.net.LinkProperties.CompareResult;
 import android.net.MobileDataStateTracker;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
@@ -260,6 +260,10 @@
 
     private InetAddress mDefaultDns;
 
+    // this collection is used to refcount the added routes - if there are none left
+    // it's time to remove the route from the route table
+    private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
+
     // used in DBG mode to track inet condition reports
     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
     private ArrayList mInetLog;
@@ -479,7 +483,7 @@
                         mNetConfigs[netType].radio);
                 continue;
             }
-            mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties();
+            mCurrentLinkProperties[netType] = null;
         }
 
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1053,62 +1057,71 @@
         }
         try {
             InetAddress addr = InetAddress.getByAddress(hostAddress);
-            return addHostRoute(tracker, addr, 0);
+            LinkProperties lp = tracker.getLinkProperties();
+            return addRoute(lp, RouteInfo.makeHostRoute(addr));
         } catch (UnknownHostException e) {}
         return false;
     }
 
-    /**
-     * Ensure that a network route exists to deliver traffic to the specified
-     * host via the mobile data network.
-     * @param hostAddress the IP address of the host to which the route is desired,
-     * in network byte order.
-     * TODO - deprecate
-     * @return {@code true} on success, {@code false} on failure
-     */
-    private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) {
-        LinkProperties lp = nt.getLinkProperties();
-        if ((lp == null) || (hostAddress == null)) return false;
-
-        String interfaceName = lp.getInterfaceName();
-        if (DBG) {
-            log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" +
-                    cycleCount);
-        }
-        if (interfaceName == null) {
-            if (DBG) loge("addHostRoute failed due to null interface name");
-            return false;
-        }
-
-        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress);
-        InetAddress gatewayAddress = null;
-        if (bestRoute != null) {
-            gatewayAddress = bestRoute.getGateway();
-            // if the best route is ourself, don't relf-reference, just add the host route
-            if (hostAddress.equals(gatewayAddress)) gatewayAddress = null;
-        }
-        if (gatewayAddress != null) {
-            if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
-                loge("Error adding hostroute - too much recursion");
-                return false;
-            }
-            if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false;
-        }
-
-        RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress);
-
-        try {
-            mNetd.addRoute(interfaceName, route);
-            return true;
-        } catch (Exception ex) {
-            return false;
-        }
+    private boolean addRoute(LinkProperties p, RouteInfo r) {
+        return modifyRoute(p.getInterfaceName(), p, r, 0, true);
     }
 
-    // TODO support the removal of single host routes.  Keep a ref count of them so we
-    // aren't over-zealous
-    private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
-        return false;
+    private boolean removeRoute(LinkProperties p, RouteInfo r) {
+        return modifyRoute(p.getInterfaceName(), p, r, 0, false);
+    }
+
+    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
+            boolean doAdd) {
+        if ((ifaceName == null) || (lp == null) || (r == null)) return false;
+
+        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
+            loge("Error adding route - too much recursion");
+            return false;
+        }
+
+        if (r.isHostRoute() == false) {
+            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
+            if (bestRoute != null) {
+                if (bestRoute.getGateway().equals(r.getGateway())) {
+                    // if there is no better route, add the implied hostroute for our gateway
+                    bestRoute = RouteInfo.makeHostRoute(r.getGateway());
+                } else {
+                    // if we will connect to our gateway through another route, add a direct
+                    // route to it's gateway
+                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
+                }
+                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd);
+            }
+        }
+        if (doAdd) {
+            if (DBG) log("Adding " + r + " for interface " + ifaceName);
+            mAddedRoutes.add(r);
+            try {
+                mNetd.addRoute(ifaceName, r);
+            } catch (Exception e) {
+                // never crash - catch them all
+                loge("Exception trying to add a route: " + e);
+                return false;
+            }
+        } else {
+            // if we remove this one and there are no more like it, then refcount==0 and
+            // we can remove it from the table
+            mAddedRoutes.remove(r);
+            if (mAddedRoutes.contains(r) == false) {
+                if (DBG) log("Removing " + r + " for interface " + ifaceName);
+                try {
+                    mNetd.removeRoute(ifaceName, r);
+                } catch (Exception e) {
+                    // never crash - catch them all
+                    loge("Exception trying to remove a route: " + e);
+                    return false;
+                }
+            } else {
+                if (DBG) log("not removing " + r + " as it's still in use");
+            }
+        }
+        return true;
     }
 
     /**
@@ -1157,9 +1170,6 @@
     public void setDataDependency(int networkType, boolean met) {
         enforceConnectivityInternalPermission();
 
-        if (DBG) {
-            log("setDataDependency(" + networkType + ", " + met + ")");
-        }
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
                 (met ? ENABLED : DISABLED), networkType));
     }
@@ -1583,10 +1593,11 @@
          */
         handleDnsConfigurationChange(netType);
 
+        LinkProperties curLp = mCurrentLinkProperties[netType];
+        LinkProperties newLp = null;
+
         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
-            LinkProperties newLp = mNetTrackers[netType].getLinkProperties();
-            LinkProperties curLp = mCurrentLinkProperties[netType];
-            mCurrentLinkProperties[netType] = newLp;
+            newLp = mNetTrackers[netType].getLinkProperties();
             if (VDBG) {
                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
                         " doReset=" + doReset + " resetMask=" + resetMask +
@@ -1594,61 +1605,50 @@
                         "\n   newLp=" + newLp);
             }
 
-            if (curLp.isIdenticalInterfaceName(newLp)) {
-                CompareAddressesResult car = curLp.compareAddresses(newLp);
-                if ((car.removed.size() != 0) || (car.added.size() != 0)) {
-                    for (LinkAddress linkAddr : car.removed) {
-                        if (linkAddr.getAddress() instanceof Inet4Address) {
-                            resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
+            if (curLp != null) {
+                if (curLp.isIdenticalInterfaceName(newLp)) {
+                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
+                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
+                        for (LinkAddress linkAddr : car.removed) {
+                            if (linkAddr.getAddress() instanceof Inet4Address) {
+                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
+                            }
+                            if (linkAddr.getAddress() instanceof Inet6Address) {
+                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
+                            }
                         }
-                        if (linkAddr.getAddress() instanceof Inet6Address) {
-                            resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
+                        if (DBG) {
+                            log("handleConnectivityChange: addresses changed" +
+                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
+                                    "\n   car=" + car);
                         }
-                    }
-                    if (DBG) {
-                        log("handleConnectivityChange: addresses changed" +
-                                " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
-                                "\n   car=" + car);
+                    } else {
+                        if (DBG) {
+                            log("handleConnectivityChange: address are the same reset per doReset" +
+                                   " linkProperty[" + netType + "]:" +
+                                   " resetMask=" + resetMask);
+                        }
                     }
                 } else {
-                    if (DBG) {
-                        log("handleConnectivityChange: address are the same reset per doReset" +
-                               " linkProperty[" + netType + "]:" +
-                               " resetMask=" + resetMask);
-                    }
+                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
+                    log("handleConnectivityChange: interface not not equivalent reset both" +
+                            " linkProperty[" + netType + "]:" +
+                            " resetMask=" + resetMask);
                 }
-            } else {
-                resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
-                log("handleConnectivityChange: interface not not equivalent reset both" +
-                        " linkProperty[" + netType + "]:" +
-                        " resetMask=" + resetMask);
             }
             if (mNetConfigs[netType].isDefault()) {
                 handleApplyDefaultProxy(netType);
-                addDefaultRoute(mNetTrackers[netType]);
-            } else {
-                // many radios add a default route even when we don't want one.
-                // remove the default route unless we need it for our active network
-                if (mActiveDefaultNetwork != -1) {
-                    LinkProperties defaultLinkProperties =
-                            mNetTrackers[mActiveDefaultNetwork].getLinkProperties();
-                    LinkProperties newLinkProperties =
-                            mNetTrackers[netType].getLinkProperties();
-                    String defaultIface = defaultLinkProperties.getInterfaceName();
-                    if (defaultIface != null &&
-                            !defaultIface.equals(newLinkProperties.getInterfaceName())) {
-                        removeDefaultRoute(mNetTrackers[netType]);
-                    }
-                }
-                addPrivateDnsRoutes(mNetTrackers[netType]);
             }
         } else {
-            if (mNetConfigs[netType].isDefault()) {
-                removeDefaultRoute(mNetTrackers[netType]);
-            } else {
-                removePrivateDnsRoutes(mNetTrackers[netType]);
+            if (VDBG) {
+                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+                        " doReset=" + doReset + " resetMask=" + resetMask +
+                        "\n  curLp=" + curLp +
+                        "\n  newLp= null");
             }
         }
+        mCurrentLinkProperties[netType] = newLp;
+        updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
 
         if (doReset || resetMask != 0) {
             LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
@@ -1672,108 +1672,64 @@
         }
     }
 
-    private void addPrivateDnsRoutes(NetworkStateTracker nt) {
-        boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
-        LinkProperties p = nt.getLinkProperties();
-        if (p == null) return;
-        String interfaceName = p.getInterfaceName();
+    /**
+     * Add and remove routes using the old properties (null if not previously connected),
+     * new properties (null if becoming disconnected).  May even be double null, which
+     * is a noop.
+     * Uses isLinkDefault to determine if default routes should be set or conversely if
+     * host routes should be set to the dns servers
+     */
+    private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) {
+        Collection<RouteInfo> routesToAdd = null;
+        CompareResult<InetAddress> dnsDiff = null;
 
-        if (DBG) {
-            log("addPrivateDnsRoutes for " + nt +
-                    "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
-        }
-        if (interfaceName != null && !privateDnsRouteSet) {
-            Collection<InetAddress> dnsList = p.getDnses();
-            for (InetAddress dns : dnsList) {
-                addHostRoute(nt, dns, 0);
-            }
-            nt.privateDnsRouteSet(true);
-        }
-    }
+        if (curLp != null) {
+            // check for the delta between the current set and the new
+            CompareResult<RouteInfo> routeDiff = curLp.compareRoutes(newLp);
+            dnsDiff = curLp.compareDnses(newLp);
 
-    private void removePrivateDnsRoutes(NetworkStateTracker nt) {
-        LinkProperties p = nt.getLinkProperties();
-        if (p == null) return;
-        String interfaceName = p.getInterfaceName();
-        boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
-        if (interfaceName != null && privateDnsRouteSet) {
-            if (DBG) {
-                log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
-                        " (" + interfaceName + ")");
-            }
-
-            Collection<InetAddress> dnsList = p.getDnses();
-            for (InetAddress dns : dnsList) {
-                if (DBG) log("  removing " + dns);
-                RouteInfo route = RouteInfo.makeHostRoute(dns);
-                try {
-                    mNetd.removeRoute(interfaceName, route);
-                } catch (Exception ex) {
-                    loge("error (" + ex + ") removing dns route " + route);
+            for (RouteInfo r : routeDiff.removed) {
+                if (isLinkDefault || ! r.isDefaultRoute()) {
+                    removeRoute(curLp, r);
                 }
             }
-            nt.privateDnsRouteSet(false);
+            routesToAdd = routeDiff.added;
         }
-    }
 
+        if (newLp != null) {
+            // if we didn't get a diff from cur -> new, then just use the new
+            if (routesToAdd == null) {
+                routesToAdd = newLp.getRoutes();
+            }
 
-    private void addDefaultRoute(NetworkStateTracker nt) {
-        LinkProperties p = nt.getLinkProperties();
-        if (p == null) return;
-        String interfaceName = p.getInterfaceName();
-        if (TextUtils.isEmpty(interfaceName)) return;
+            for (RouteInfo r :  routesToAdd) {
+                if (isLinkDefault || ! r.isDefaultRoute()) {
+                    addRoute(newLp, r);
+                }
+            }
+        }
 
-        for (RouteInfo route : p.getRoutes()) {
-            //TODO - handle non-default routes
-            if (route.isDefaultRoute()) {
-                if (DBG) log("adding default route " + route);
-                InetAddress gateway = route.getGateway();
-                if (addHostRoute(nt, gateway, 0)) {
-                    try {
-                        mNetd.addRoute(interfaceName, route);
-                    } catch (Exception e) {
-                        loge("error adding default route " + route);
-                        continue;
-                    }
-                    if (DBG) {
-                        NetworkInfo networkInfo = nt.getNetworkInfo();
-                        log("addDefaultRoute for " + networkInfo.getTypeName() +
-                                " (" + interfaceName + "), GatewayAddr=" +
-                                gateway.getHostAddress());
-                    }
-                } else {
-                    loge("error adding host route for default route " + route);
+        if (!isLinkDefault) {
+            // handle DNS routes
+            Collection<InetAddress> dnsToAdd = null;
+            if (dnsDiff != null) {
+                dnsToAdd = dnsDiff.added;
+                for (InetAddress dnsAddress : dnsDiff.removed) {
+                    removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress));
+                }
+            }
+            if (newLp != null) {
+                if (dnsToAdd == null) {
+                    dnsToAdd = newLp.getDnses();
+                }
+                for(InetAddress dnsAddress : dnsToAdd) {
+                    addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress));
                 }
             }
         }
     }
 
 
-    public void removeDefaultRoute(NetworkStateTracker nt) {
-        LinkProperties p = nt.getLinkProperties();
-        if (p == null) return;
-        String interfaceName = p.getInterfaceName();
-
-        if (interfaceName == null) return;
-
-        for (RouteInfo route : p.getRoutes()) {
-            //TODO - handle non-default routes
-            if (route.isDefaultRoute()) {
-                try {
-                    mNetd.removeRoute(interfaceName, route);
-                } catch (Exception ex) {
-                    loge("error (" + ex + ") removing default route " + route);
-                    continue;
-                }
-                if (DBG) {
-                    NetworkInfo networkInfo = nt.getNetworkInfo();
-                    log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
-                            interfaceName + ")");
-                }
-            }
-        }
-    }
-
    /**
      * Reads the network specific TCP buffer sizes from SystemProperties
      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
@@ -2528,8 +2484,23 @@
      * @hide
      */
     @Override
-    public void protectVpn(ParcelFileDescriptor socket) {
-        mVpn.protect(socket, getDefaultInterface());
+    public boolean protectVpn(ParcelFileDescriptor socket) {
+        try {
+            int type = mActiveDefaultNetwork;
+            if (ConnectivityManager.isNetworkTypeValid(type)) {
+                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
+                return true;
+            }
+        } catch (Exception e) {
+            // ignore
+        } finally {
+            try {
+                socket.close();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return false;
     }
 
     /**
@@ -2577,19 +2548,6 @@
         return mVpn.getLegacyVpnInfo();
     }
 
-    private String getDefaultInterface() {
-        if (ConnectivityManager.isNetworkTypeValid(mActiveDefaultNetwork)) {
-            NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
-            if (tracker != null) {
-                LinkProperties properties = tracker.getLinkProperties();
-                if (properties != null) {
-                    return properties.getInterfaceName();
-                }
-            }
-        }
-        throw new IllegalStateException("No default interface");
-    }
-
     /**
      * Callback for VPN subsystem. Currently VPN is not adapted to the service
      * through NetworkStateTracker since it works differently. For example, it
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index fd93bcf..f546cf1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -18,10 +18,10 @@
 
 import com.android.internal.R;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.ProcessStats;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
 import com.android.server.ProcessMap;
-import com.android.server.ProcessStats;
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index c185012..05e95a7 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -41,6 +41,9 @@
 import com.android.internal.net.VpnConfig;
 import com.android.server.ConnectivityService.VpnCallback;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.Charsets;
 import java.util.Arrays;
@@ -67,22 +70,14 @@
 
     /**
      * Protect a socket from routing changes by binding it to the given
-     * interface. The socket IS closed by this method.
+     * interface. The socket is NOT closed by this method.
      *
      * @param socket The socket to be bound.
      * @param name The name of the interface.
      */
     public void protect(ParcelFileDescriptor socket, String interfaze) {
-        try {
-            mContext.enforceCallingPermission(VPN, "protect");
-            jniProtect(socket.getFd(), interfaze);
-        } finally {
-            try {
-                socket.close();
-            } catch (Exception e) {
-                // ignore
-            }
-        }
+        mContext.enforceCallingPermission(VPN, "protect");
+        jniProtect(socket.getFd(), interfaze);
     }
 
     /**
@@ -192,10 +187,15 @@
         }
 
         // Configure the interface. Abort if any of these steps fails.
-        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(
-                jniConfigure(config.mtu, config.addresses, config.routes));
+        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
         try {
             String interfaze = jniGetName(tun.getFd());
+            if (jniSetAddresses(interfaze, config.addresses) < 1) {
+                throw new IllegalArgumentException("At least one address must be specified");
+            }
+            if (config.routes != null) {
+                jniSetRoutes(interfaze, config.routes);
+            }
             if (mInterface != null && !mInterface.equals(interfaze)) {
                 jniReset(mInterface);
             }
@@ -222,18 +222,24 @@
     }
 
     // INetworkManagementEventObserver.Stub
-    public void interfaceStatusChanged(String interfaze, boolean up) {
-    }
-
-    // INetworkManagementEventObserver.Stub
-    public void interfaceLinkStateChanged(String interfaze, boolean up) {
-    }
-
-    // INetworkManagementEventObserver.Stub
     public void interfaceAdded(String interfaze) {
     }
 
     // INetworkManagementEventObserver.Stub
+    public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
+        if (!up && mLegacyVpnRunner != null) {
+            mLegacyVpnRunner.check(interfaze);
+        }
+    }
+
+    // INetworkManagementEventObserver.Stub
+    public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) {
+        if (!up && mLegacyVpnRunner != null) {
+            mLegacyVpnRunner.check(interfaze);
+        }
+    }
+
+    // INetworkManagementEventObserver.Stub
     public synchronized void interfaceRemoved(String interfaze) {
         if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
             mCallback.restore();
@@ -279,8 +285,10 @@
         }
     }
 
-    private native int jniConfigure(int mtu, String addresses, String routes);
+    private native int jniCreate(int mtu);
     private native String jniGetName(int tun);
+    private native int jniSetAddresses(String interfaze, String addresses);
+    private native int jniSetRoutes(String interfaze, String routes);
     private native void jniReset(String interfaze);
     private native int jniCheck(String interfaze);
     private native void jniProtect(int socket, String interfaze);
@@ -323,11 +331,11 @@
      */
     private class LegacyVpnRunner extends Thread {
         private static final String TAG = "LegacyVpnRunner";
-        private static final String NONE = "--";
 
         private final VpnConfig mConfig;
         private final String[] mDaemons;
         private final String[][] mArguments;
+        private final String mOuterInterface;
         private final LegacyVpnInfo mInfo;
 
         private long mTimer = -1;
@@ -339,17 +347,27 @@
             mArguments = new String[][] {racoon, mtpd};
             mInfo = new LegacyVpnInfo();
 
+            // This is the interface which VPN is running on.
+            mOuterInterface = mConfig.interfaze;
+
             // Legacy VPN is not a real package, so we use it to carry the key.
             mInfo.key = mConfig.packagz;
             mConfig.packagz = VpnConfig.LEGACY_VPN;
         }
 
+        public void check(String interfaze) {
+            if (interfaze.equals(mOuterInterface)) {
+                Log.i(TAG, "Legacy VPN is going down with " + interfaze);
+                exit();
+            }
+        }
+
         public void exit() {
             // We assume that everything is reset after the daemons die.
+            interrupt();
             for (String daemon : mDaemons) {
                 SystemProperties.set("ctl.stop", daemon);
             }
-            interrupt();
         }
 
         public LegacyVpnInfo getInfo() {
@@ -380,7 +398,7 @@
                 Thread.sleep(yield ? 200 : 1);
             } else {
                 mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
-                throw new IllegalStateException("time is up");
+                throw new IllegalStateException("Time is up");
             }
         }
 
@@ -404,12 +422,11 @@
                     }
                 }
 
-                // Reset the properties.
-                SystemProperties.set("vpn.dns", NONE);
-                SystemProperties.set("vpn.via", NONE);
-                while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
-                        !NONE.equals(SystemProperties.get("vpn.via"))) {
-                    checkpoint(true);
+                // Clear the previous state.
+                File state = new File("/data/misc/vpn/state");
+                state.delete();
+                if (state.exists()) {
+                    throw new IllegalStateException("Cannot delete the state");
                 }
 
                 // Check if we need to restart any of the daemons.
@@ -461,29 +478,34 @@
                     OutputStream out = socket.getOutputStream();
                     for (String argument : arguments) {
                         byte[] bytes = argument.getBytes(Charsets.UTF_8);
-                        if (bytes.length >= 0xFFFF) {
-                            throw new IllegalArgumentException("argument is too large");
+                        if (bytes.length > 0xFFFF) {
+                            throw new IllegalArgumentException("Argument is too large");
                         }
                         out.write(bytes.length >> 8);
                         out.write(bytes.length);
                         out.write(bytes);
                         checkpoint(false);
                     }
-
-                    // Send End-Of-Arguments.
-                    out.write(0xFF);
-                    out.write(0xFF);
                     out.flush();
+                    socket.shutdownOutput();
+
+                    // Wait for End-of-File.
+                    InputStream in = socket.getInputStream();
+                    while (true) {
+                        try {
+                            if (in.read() == -1) {
+                                break;
+                            }
+                        } catch (Exception e) {
+                            // ignore
+                        }
+                        checkpoint(true);
+                    }
                     socket.close();
                 }
 
-                // Now here is the beast from the old days. We check few
-                // properties to figure out the current status. Ideally we
-                // can read things back from the sockets and get rid of the
-                // properties, but we have no time...
-                while (NONE.equals(SystemProperties.get("vpn.dns")) ||
-                        NONE.equals(SystemProperties.get("vpn.via"))) {
-
+                // Wait for the daemons to create the new state.
+                while (!state.exists()) {
                     // Check if a running daemon is dead.
                     for (int i = 0; i < mDaemons.length; ++i) {
                         String daemon = mDaemons[i];
@@ -495,20 +517,45 @@
                     checkpoint(true);
                 }
 
-                // Now we are connected. Get the interface.
-                mConfig.interfaze = SystemProperties.get("vpn.via");
+                // Now we are connected. Read and parse the new state.
+                byte[] buffer = new byte[(int) state.length()];
+                if (new FileInputStream(state).read(buffer) != buffer.length) {
+                    throw new IllegalStateException("Cannot read the state");
+                }
+                String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1);
+                if (parameters.length != 6) {
+                    throw new IllegalStateException("Cannot parse the state");
+                }
 
-                // Get the DNS servers if they are not set in config.
+                // Set the interface and the addresses in the config.
+                mConfig.interfaze = parameters[0].trim();
+                mConfig.addresses = parameters[1].trim();
+
+                // Set the routes if they are not set in the config.
+                if (mConfig.routes == null || mConfig.routes.isEmpty()) {
+                    mConfig.routes = parameters[2].trim();
+                }
+
+                // Set the DNS servers if they are not set in the config.
                 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
-                    String dnsServers = SystemProperties.get("vpn.dns").trim();
+                    String dnsServers = parameters[3].trim();
                     if (!dnsServers.isEmpty()) {
                         mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
                     }
                 }
 
-                // TODO: support search domains from ISAKMP mode config.
+                // Set the search domains if they are not set in the config.
+                if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
+                    String searchDomains = parameters[4].trim();
+                    if (!searchDomains.isEmpty()) {
+                        mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
+                    }
+                }
 
-                // The final step must be synchronized.
+                // Set the routes.
+                jniSetRoutes(mConfig.interfaze, mConfig.routes);
+
+                // Here is the last step and it must be done synchronously.
                 synchronized (Vpn.this) {
                     // Check if the thread is interrupted while we are waiting.
                     checkpoint(false);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index d30b66b..0c78fe7 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -24,8 +24,8 @@
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
+import static android.net.ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.*;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -42,7 +42,7 @@
 import static android.net.NetworkPolicyManager.isUidValidForPolicy;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
@@ -678,7 +678,7 @@
             time.setToNow();
             final int cycleDay = time.monthDay;
 
-            final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
+            final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
             mNetworkPolicy.add(
                     new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
             writePolicyLocked();
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 54e94db..7ec6b81 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -73,11 +73,12 @@
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -719,10 +720,9 @@
         // clear any existing stats and read from disk
         mNetworkStats.clear();
 
-        FileInputStream fis = null;
+        DataInputStream in = null;
         try {
-            fis = mNetworkFile.openRead();
-            final DataInputStream in = new DataInputStream(fis);
+            in = new DataInputStream(new BufferedInputStream(mNetworkFile.openRead()));
 
             // verify file magic header intact
             final int magic = in.readInt();
@@ -751,7 +751,7 @@
         } catch (IOException e) {
             Slog.e(TAG, "problem reading network stats", e);
         } finally {
-            IoUtils.closeQuietly(fis);
+            IoUtils.closeQuietly(in);
         }
     }
 
@@ -768,10 +768,9 @@
         // clear any existing stats and read from disk
         mUidStats.clear();
 
-        FileInputStream fis = null;
+        DataInputStream in = null;
         try {
-            fis = mUidFile.openRead();
-            final DataInputStream in = new DataInputStream(fis);
+            in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
 
             // verify file magic header intact
             final int magic = in.readInt();
@@ -826,7 +825,7 @@
         } catch (IOException e) {
             Slog.e(TAG, "problem reading uid stats", e);
         } finally {
-            IoUtils.closeQuietly(fis);
+            IoUtils.closeQuietly(in);
         }
     }
 
@@ -838,7 +837,7 @@
         FileOutputStream fos = null;
         try {
             fos = mNetworkFile.startWrite();
-            final DataOutputStream out = new DataOutputStream(fos);
+            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
 
             out.writeInt(FILE_MAGIC);
             out.writeInt(VERSION_NETWORK_INIT);
@@ -850,6 +849,7 @@
                 history.writeToStream(out);
             }
 
+            out.flush();
             mNetworkFile.finishWrite(fos);
         } catch (IOException e) {
             if (fos != null) {
@@ -871,7 +871,7 @@
         FileOutputStream fos = null;
         try {
             fos = mUidFile.startWrite();
-            final DataOutputStream out = new DataOutputStream(fos);
+            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
 
             out.writeInt(FILE_MAGIC);
             out.writeInt(VERSION_UID_WITH_TAG);
@@ -895,6 +895,7 @@
                 }
             }
 
+            out.flush();
             mUidFile.finishWrite(fos);
         } catch (IOException e) {
             if (fos != null) {
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 5f920f1..d28a6b4 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_TAG "VpnJni"
 #include <cutils/log.h>
-#include <cutils/properties.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -54,7 +53,7 @@
 #define SYSTEM_ERROR -1
 #define BAD_ARGUMENT -2
 
-static int create_interface(char *name, int *index, int mtu)
+static int create_interface(int mtu)
 {
     int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
 
@@ -82,14 +81,6 @@
         goto error;
     }
 
-    // Get interface index.
-    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
-        LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
-        goto error;
-    }
-
-    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
-    *index = ifr4.ifr_ifindex;
     return tun;
 
 error:
@@ -97,12 +88,40 @@
     return SYSTEM_ERROR;
 }
 
-static int set_addresses(const char *name, int index, const char *addresses)
+static int get_interface_name(char *name, int tun)
 {
     ifreq ifr4;
+    if (ioctl(tun, TUNGETIFF, &ifr4)) {
+        LOGE("Cannot get interface name: %s", strerror(errno));
+        return SYSTEM_ERROR;
+    }
+    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+    return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+    ifreq ifr4;
+    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+        LOGE("Cannot get index of %s: %s", name, strerror(errno));
+        return SYSTEM_ERROR;
+    }
+    return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+    int index = get_interface_index(name);
+    if (index < 0) {
+        return index;
+    }
+
+    ifreq ifr4;
     memset(&ifr4, 0, sizeof(ifr4));
     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
     ifr4.ifr_addr.sa_family = AF_INET;
+    ifr4.ifr_netmask.sa_family = AF_INET;
 
     in6_ifreq ifr6;
     memset(&ifr6, 0, sizeof(ifr6));
@@ -146,7 +165,7 @@
             }
 
             in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
-            *as_in_addr(&ifr4.ifr_addr) = htonl(mask);
+            *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
             if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
                 break;
@@ -168,8 +187,13 @@
     return count;
 }
 
-static int set_routes(const char *name, int index, const char *routes)
+static int set_routes(const char *name, const char *routes)
 {
+    int index = get_interface_index(name);
+    if (index < 0) {
+        return index;
+    }
+
     rtentry rt4;
     memset(&rt4, 0, sizeof(rt4));
     rt4.rt_dev = (char *)name;
@@ -253,17 +277,6 @@
     return count;
 }
 
-static int get_interface_name(char *name, int tun)
-{
-    ifreq ifr4;
-    if (ioctl(tun, TUNGETIFF, &ifr4)) {
-        LOGE("Cannot get interface name: %s", strerror(errno));
-        return SYSTEM_ERROR;
-    }
-    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
-    return 0;
-}
-
 static int reset_interface(const char *name)
 {
     ifreq ifr4;
@@ -309,53 +322,14 @@
     }
 }
 
-static jint configure(JNIEnv *env, jobject thiz,
-        jint mtu, jstring jAddresses, jstring jRoutes)
+static jint create(JNIEnv *env, jobject thiz, jint mtu)
 {
-    char name[IFNAMSIZ];
-    int index;
-    int tun = create_interface(name, &index, mtu);
+    int tun = create_interface(mtu);
     if (tun < 0) {
         throwException(env, tun, "Cannot create interface");
         return -1;
     }
-
-    const char *addresses = NULL;
-    const char *routes = NULL;
-    int count;
-
-    // At least one address must be set.
-    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
-    if (!addresses) {
-        jniThrowNullPointerException(env, "address");
-        goto error;
-    }
-    count = set_addresses(name, index, addresses);
-    env->ReleaseStringUTFChars(jAddresses, addresses);
-    if (count <= 0) {
-        throwException(env, count, "Cannot set address");
-        goto error;
-    }
-    LOGD("Configured %d address(es) on %s", count, name);
-
-    // On the contrary, routes are optional.
-    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
-    if (routes) {
-        count = set_routes(name, index, routes);
-        env->ReleaseStringUTFChars(jRoutes, routes);
-        if (count < 0) {
-            throwException(env, count, "Cannot set route");
-            goto error;
-        }
-        LOGD("Configured %d route(s) on %s", count, name);
-    }
-
     return tun;
-
-error:
-    close(tun);
-    LOGD("%s is destroyed", name);
-    return -1;
 }
 
 static jstring getName(JNIEnv *env, jobject thiz, jint tun)
@@ -368,6 +342,72 @@
     return env->NewStringUTF(name);
 }
 
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+        jstring jAddresses)
+{
+    const char *name = NULL;
+    const char *addresses = NULL;
+    int count = -1;
+
+    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+    if (!name) {
+        jniThrowNullPointerException(env, "name");
+        goto error;
+    }
+    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+    if (!addresses) {
+        jniThrowNullPointerException(env, "addresses");
+        goto error;
+    }
+    count = set_addresses(name, addresses);
+    if (count < 0) {
+        throwException(env, count, "Cannot set address");
+        count = -1;
+    }
+
+error:
+    if (name) {
+        env->ReleaseStringUTFChars(jName, name);
+    }
+    if (addresses) {
+        env->ReleaseStringUTFChars(jAddresses, addresses);
+    }
+    return count;
+}
+
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+        jstring jRoutes)
+{
+    const char *name = NULL;
+    const char *routes = NULL;
+    int count = -1;
+
+    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+    if (!name) {
+        jniThrowNullPointerException(env, "name");
+        goto error;
+    }
+    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+    if (!routes) {
+        jniThrowNullPointerException(env, "routes");
+        goto error;
+    }
+    count = set_routes(name, routes);
+    if (count < 0) {
+        throwException(env, count, "Cannot set route");
+        count = -1;
+    }
+
+error:
+    if (name) {
+        env->ReleaseStringUTFChars(jName, name);
+    }
+    if (routes) {
+        env->ReleaseStringUTFChars(jRoutes, routes);
+    }
+    return count;
+}
+
 static void reset(JNIEnv *env, jobject thiz, jstring jName)
 {
     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
@@ -409,8 +449,10 @@
 //------------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure},
+    {"jniCreate", "(I)I", (void *)create},
     {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
+    {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+    {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
     {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
     {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
     {"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 4ec0c8c..518a1bb7 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -28,23 +28,25 @@
       mEnabled(false), mGyroTime(0)
 {
     sensor_t const* list;
-    size_t count = mSensorDevice.getSensorList(&list);
-    for (size_t i=0 ; i<count ; i++) {
-        if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
-            mAcc = Sensor(list + i);
+    ssize_t count = mSensorDevice.getSensorList(&list);
+    if (count > 0) {
+        for (size_t i=0 ; i<size_t(count) ; i++) {
+            if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+                mAcc = Sensor(list + i);
+            }
+            if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
+                mMag = Sensor(list + i);
+            }
+            if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+                mGyro = Sensor(list + i);
+                // 200 Hz for gyro events is a good compromise between precision
+                // and power/cpu usage.
+                mGyroRate = 200;
+                mTargetDelayNs = 1000000000LL/mGyroRate;
+            }
         }
-        if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
-            mMag = Sensor(list + i);
-        }
-        if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
-            mGyro = Sensor(list + i);
-            // 200 Hz for gyro events is a good compromise between precision
-            // and power/cpu usage.
-            mGyroRate = 200;
-            mTargetDelayNs = 1000000000LL/mGyroRate;
-        }
+        mFusion.init();
     }
-    mFusion.init();
 }
 
 void SensorFusion::process(const sensors_event_t& event) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 64d214b..e0dce1f 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -70,73 +70,76 @@
     SensorDevice& dev(SensorDevice::getInstance());
 
     if (dev.initCheck() == NO_ERROR) {
-        ssize_t orientationIndex = -1;
-        bool hasGyro = false;
-        uint32_t virtualSensorsNeeds =
-                (1<<SENSOR_TYPE_GRAVITY) |
-                (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
-                (1<<SENSOR_TYPE_ROTATION_VECTOR);
         sensor_t const* list;
-        int count = dev.getSensorList(&list);
-        mLastEventSeen.setCapacity(count);
-        for (int i=0 ; i<count ; i++) {
-            registerSensor( new HardwareSensor(list[i]) );
-            switch (list[i].type) {
-                case SENSOR_TYPE_ORIENTATION:
-                    orientationIndex = i;
-                    break;
-                case SENSOR_TYPE_GYROSCOPE:
-                    hasGyro = true;
-                    break;
-                case SENSOR_TYPE_GRAVITY:
-                case SENSOR_TYPE_LINEAR_ACCELERATION:
-                case SENSOR_TYPE_ROTATION_VECTOR:
-                    virtualSensorsNeeds &= ~(1<<list[i].type);
-                    break;
+        ssize_t count = dev.getSensorList(&list);
+        if (count > 0) {
+            ssize_t orientationIndex = -1;
+            bool hasGyro = false;
+            uint32_t virtualSensorsNeeds =
+                    (1<<SENSOR_TYPE_GRAVITY) |
+                    (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
+                    (1<<SENSOR_TYPE_ROTATION_VECTOR);
+
+            mLastEventSeen.setCapacity(count);
+            for (ssize_t i=0 ; i<count ; i++) {
+                registerSensor( new HardwareSensor(list[i]) );
+                switch (list[i].type) {
+                    case SENSOR_TYPE_ORIENTATION:
+                        orientationIndex = i;
+                        break;
+                    case SENSOR_TYPE_GYROSCOPE:
+                        hasGyro = true;
+                        break;
+                    case SENSOR_TYPE_GRAVITY:
+                    case SENSOR_TYPE_LINEAR_ACCELERATION:
+                    case SENSOR_TYPE_ROTATION_VECTOR:
+                        virtualSensorsNeeds &= ~(1<<list[i].type);
+                        break;
+                }
             }
-        }
 
-        // it's safe to instantiate the SensorFusion object here
-        // (it wants to be instantiated after h/w sensors have been
-        // registered)
-        const SensorFusion& fusion(SensorFusion::getInstance());
+            // it's safe to instantiate the SensorFusion object here
+            // (it wants to be instantiated after h/w sensors have been
+            // registered)
+            const SensorFusion& fusion(SensorFusion::getInstance());
 
-        if (hasGyro) {
-            // Always instantiate Android's virtual sensors. Since they are
-            // instantiated behind sensors from the HAL, they won't
-            // interfere with applications, unless they looks specifically
-            // for them (by name).
+            if (hasGyro) {
+                // Always instantiate Android's virtual sensors. Since they are
+                // instantiated behind sensors from the HAL, they won't
+                // interfere with applications, unless they looks specifically
+                // for them (by name).
 
-            registerVirtualSensor( new RotationVectorSensor() );
-            registerVirtualSensor( new GravitySensor(list, count) );
-            registerVirtualSensor( new LinearAccelerationSensor(list, count) );
+                registerVirtualSensor( new RotationVectorSensor() );
+                registerVirtualSensor( new GravitySensor(list, count) );
+                registerVirtualSensor( new LinearAccelerationSensor(list, count) );
 
-            // these are optional
-            registerVirtualSensor( new OrientationSensor() );
-            registerVirtualSensor( new CorrectedGyroSensor(list, count) );
+                // these are optional
+                registerVirtualSensor( new OrientationSensor() );
+                registerVirtualSensor( new CorrectedGyroSensor(list, count) );
 
-            // virtual debugging sensors...
-            char value[PROPERTY_VALUE_MAX];
-            property_get("debug.sensors", value, "0");
-            if (atoi(value)) {
-                registerVirtualSensor( new GyroDriftSensor() );
+                // virtual debugging sensors...
+                char value[PROPERTY_VALUE_MAX];
+                property_get("debug.sensors", value, "0");
+                if (atoi(value)) {
+                    registerVirtualSensor( new GyroDriftSensor() );
+                }
             }
-        }
 
-        // build the sensor list returned to users
-        mUserSensorList = mSensorList;
-        if (hasGyro &&
-                (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
-            // if we have the fancy sensor fusion, and it's not provided by the
-            // HAL, use our own (fused) orientation sensor by removing the
-            // HAL supplied one form the user list.
-            if (orientationIndex >= 0) {
-                mUserSensorList.removeItemsAt(orientationIndex);
+            // build the sensor list returned to users
+            mUserSensorList = mSensorList;
+            if (hasGyro &&
+                    (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
+                // if we have the fancy sensor fusion, and it's not provided by the
+                // HAL, use our own (fused) orientation sensor by removing the
+                // HAL supplied one form the user list.
+                if (orientationIndex >= 0) {
+                    mUserSensorList.removeItemsAt(orientationIndex);
+                }
             }
-        }
 
-        run("SensorService", PRIORITY_URGENT_DISPLAY);
-        mInitCheck = NO_ERROR;
+            run("SensorService", PRIORITY_URGENT_DISPLAY);
+            mInitCheck = NO_ERROR;
+        }
     }
 }
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 33fd355..504ba42 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -27,7 +27,6 @@
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.MATCH_WIFI;
 import static org.easymock.EasyMock.anyInt;
 import static org.easymock.EasyMock.aryEq;
 import static org.easymock.EasyMock.capture;
@@ -88,7 +87,7 @@
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
 
-    private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
+    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi();
 
     private BroadcastInterceptingContext mServiceContext;
     private File mPolicyDir;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index ac74063..bd80af9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -25,8 +25,8 @@
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-import static android.net.NetworkTemplate.MATCH_WIFI;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
@@ -81,9 +81,9 @@
     private static final String IMSI_1 = "310004";
     private static final String IMSI_2 = "310260";
 
-    private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
-    private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_1);
-    private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_2);
+    private static NetworkTemplate sTemplateWifi = buildTemplateWifi();
+    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
+    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
 
     private static final int UID_RED = 1001;
     private static final int UID_BLUE = 1002;
@@ -290,7 +290,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
+        history = mService.getHistoryForNetwork(sTemplateWifi);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
         assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
         assertEquals(2, history.size());
@@ -307,7 +307,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify identical stats, but spread across 4 buckets now
-        history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
+        history = mService.getHistoryForNetwork(sTemplateWifi);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
         assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
         assertEquals(4, history.size());
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 1bba8e3..8978f1d 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -26,7 +26,6 @@
 import android.app.PendingIntent;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
-import android.net.LinkProperties.CompareAddressesResult;
 import android.net.ProxyProperties;
 import android.os.AsyncResult;
 import android.os.Message;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 9e185e5..a9f2cd1 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -23,7 +23,6 @@
 import android.app.PendingIntent;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
-import android.net.LinkProperties.CompareAddressesResult;
 import android.net.ProxyProperties;
 import android.os.Message;
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index bf964b7..ccdb0bf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -27,7 +27,7 @@
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
-import android.net.LinkProperties.CompareAddressesResult;
+import android.net.LinkProperties.CompareResult;
 import android.net.NetworkUtils;
 import android.net.ProxyProperties;
 import android.net.TrafficStats;
@@ -1152,7 +1152,7 @@
                                     ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
                                     ! result.oldLp.isIdenticalAddresses(result.newLp)) {
                                 // If the same address type was removed and added we need to cleanup
-                                CompareAddressesResult car =
+                                CompareResult<LinkAddress> car =
                                     result.oldLp.compareAddresses(result.newLp);
                                 boolean needToClean = false;
                                 for (LinkAddress added : car.added) {
diff --git a/tests/BiDiTests/res/layout/textview_direction_ltr.xml b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
index f7b7b8e..2c790ec 100644
--- a/tests/BiDiTests/res/layout/textview_direction_ltr.xml
+++ b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
@@ -18,95 +18,232 @@
         android:id="@+id/textview_direction_ltr"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
-        android:layoutDirection="ltr">
+        android:layoutDirection="ltr"
+        android:textDirection="ltr">
 
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:textDirection="ltr">
-
-        <LinearLayout android:orientation="vertical"
+        <TableLayout android:orientation="vertical"
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content">
 
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="inherit"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="firstStrong"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="anyRtl"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="ltr"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="rtl"
-                    />
-        </LinearLayout>
+            <TableRow>
+                <TextView android:text="(unspecified)"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content">
+            <TableRow>
+                <TextView android:text="inherit"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="inherit"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="firstStrong"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="anyRtl"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="ltr"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="rtl"
-                    />
-        </LinearLayout>
+            <TableRow>
+                <TextView android:text="firstStrong"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-    </LinearLayout>
+            <TableRow>
+                <TextView android:text="anyRtl"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-</FrameLayout>
\ No newline at end of file
+            <TableRow>
+                <TextView android:text="ltr"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
+
+            <TableRow>
+                <TextView android:text="rtl"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginRight="7dip"
+                          android:layout_marginLeft="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
+
+        </TableLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_direction_rtl.xml b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
index 81c5411..1df100d 100644
--- a/tests/BiDiTests/res/layout/textview_direction_rtl.xml
+++ b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
@@ -18,95 +18,232 @@
         android:id="@+id/textview_direction_rtl"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
-        android:layoutDirection="rtl">
+        android:layoutDirection="rtl"
+        android:textDirection="rtl">
 
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:textDirection="rtl">
-
-        <LinearLayout android:orientation="vertical"
+        <TableLayout android:orientation="vertical"
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content">
 
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="inherit"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="firstStrong"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="anyRtl"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="ltr"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_text"
-                      android:textDirection="rtl"
-                    />
-        </LinearLayout>
+            <TableRow>
+                <TextView android:text="(unspecified)"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-        <LinearLayout android:orientation="vertical"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content">
+            <TableRow>
+                <TextView android:text="inherit"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="inherit"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="inherit"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="firstStrong"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="anyRtl"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="ltr"
-                    />
-            <TextView android:layout_height="wrap_content"
-                      android:layout_width="wrap_content"
-                      android:textSize="24dip"
-                      android:text="@string/textview_hebrew_text"
-                      android:textDirection="rtl"
-                    />
-        </LinearLayout>
+            <TableRow>
+                <TextView android:text="firstStrong"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="firstStrong"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-    </LinearLayout>
+            <TableRow>
+                <TextView android:text="anyRtl"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="anyRtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
 
-</FrameLayout>
\ No newline at end of file
+            <TableRow>
+                <TextView android:text="ltr"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="ltr"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
+
+            <TableRow>
+                <TextView android:text="rtl"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:typeface="serif"
+                          android:layout_marginRight="7dip"
+                          android:layout_marginLeft="7dip"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_hebrew_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_latin_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+                <TextView android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:textSize="24dip"
+                          android:text="@string/textview_multiline_text"
+                          android:textDirection="rtl"
+                          android:layout_marginLeft="7dip"
+                          android:layout_marginRight="7dip"
+                          android:background="#444444"
+                          />
+            </TableRow>
+
+        </TableLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index c0bbe94..9a486c1 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -40,6 +40,6 @@
     <string name="menu_delete">Delete</string>
     <string name="textview_hebrew_text">&#x05DD;&#x05DE;ab?!</string>
     <string name="textview_latin_text">ab&#x05DD;&#x05DE;?!</string>
-    <string name="textview_multiline_text">&#x05DD;&#x05DE;?!\nab?!</string>
+    <string name="textview_multiline_text">&#x05DD;&#x05DE;?!\nab?!\n?!</string>
 </resources>