Merge change 5413 into donut

* changes:
  Need to write the correct float math.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 79588ea..62dc651 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3697,6 +3697,13 @@
          */
         Locale.setDefault(data.config.locale);
 
+        /*
+         * Update the system configuration since its preloaded and might not
+         * reflect configuration changes. The configuration object passed
+         * in AppBindData can be safely assumed to be up to date
+         */
+        Resources.getSystem().updateConfiguration(mConfiguration, null);
+
         data.info = getPackageInfoNoCheck(data.appInfo);
 
         if (data.debugMode != IApplicationThread.DEBUG_OFF) {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c064284..bc016a7 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -46,10 +46,6 @@
      * Denotes a generic operation failure.
      */
     public static final int TTS_ERROR                  = -1;
-    /**
-     * Denotes a failure due to a missing resource.
-     */
-    public static final int TTS_ERROR_MISSING_RESOURCE = -2;
 
     /**
      * Queue mode where all entries in the playback queue (media to be played
@@ -61,6 +57,39 @@
      */
     public static final int TTS_QUEUE_ADD = 1;
 
+
+    /**
+     * Denotes the language is available exactly as specified by the locale
+     */
+    public static final int TTS_LANG_COUNTRY_VAR_AVAILABLE = 2;
+
+
+    /**
+     * Denotes the language is available for the language and country specified 
+     * by the locale, but not the variant.
+     */
+    public static final int TTS_LANG_COUNTRY_AVAILABLE = 1;
+
+
+    /**
+     * Denotes the language is available for the language by the locale, 
+     * but not the country and variant.
+     */
+    public static final int TTS_LANG_AVAILABLE = 0;
+
+    /**
+     * Denotes the language data is missing.
+     */
+    public static final int TTS_LANG_MISSING_DATA = -1;
+
+    /**
+     * Denotes the language is not supported by the current TTS engine.
+     */
+    public static final int TTS_LANG_NOT_SUPPORTED = -2;
+
+
+
+
     /**
      * Called when the TTS has initialized.
      *
@@ -141,16 +170,6 @@
     }
 
 
-    private boolean dataFilesCheck() {
-        // TODO #TTS# config manager will be in settings
-        Log.i("TTS_FIXME", "FIXME in Tts: config manager will be in settings");
-        // TODO #TTS# implement checking of the correct installation of
-        //             the data files.
-
-        return true;
-    }
-
-
     private void initTts() {
         mStarted = false;
 
@@ -353,6 +372,27 @@
 
 
     /**
+     * Speaks the IPA string using the specified queuing strategy and speech
+     * parameters. Note that the speech parameters are not universally supported
+     * by all engines and will be treated as a hint. The TTS library will try to
+     * fulfill these parameters as much as possible, but there is no guarantee
+     * that the voice used will have the properties specified.
+     *
+     * @param ipaText
+     *            The string of IPA text to be spoken.
+     * @param queueMode
+     *            The queuing strategy to use.
+     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
+     * @param params
+     *            The hashmap of speech parameters to be used.
+     */
+    public void speakIpa(String ipaText, int queueMode, HashMap<String,String> params)
+    {
+        //TODO: Implement speakIpa
+    }
+
+
+    /**
      * Plays the earcon using the specified queueing mode and parameters.
      *
      * @param earcon
@@ -537,6 +577,18 @@
         }
     }
 
+    /**
+     * Checks if the specified language as represented by the locale is available.
+     *
+     * @param loc
+     *            The locale describing the language to be used.
+     */
+    public int isLanguageAvailable(Locale loc) {
+        //TODO: Implement isLanguageAvailable
+        return 0;
+    }
+
+
 
     /**
      * Speaks the given text using the specified queueing mode and parameters.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ffd4d90..429f0f9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4571,9 +4571,11 @@
                     break;
                 }
                 case SWITCH_TO_LONGPRESS: {
-                    mTouchMode = TOUCH_DONE_MODE;
-                    performLongClick();
-                    updateTextEntry();
+                    if (!mPreventDrag) {
+                        mTouchMode = TOUCH_DONE_MODE;
+                        performLongClick();
+                        updateTextEntry();
+                    }
                     break;
                 }
                 case SWITCH_TO_ENTER:
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 955475e4..bd623cd 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -41,6 +41,7 @@
 import java.util.TreeSet;
 import java.util.LinkedList;
 import java.util.HashSet;
+import java.util.ArrayList;
 
 /**
  * A Layout where the positions of the children can be described in relation to each other or to the
@@ -343,7 +344,7 @@
             ignore = findViewById(mIgnoreGravity);
         }
 
-        View[] views = mSortedVerticalChildren;
+        View[] views = mSortedHorizontalChildren;
         int count = views.length;
         for (int i = 0; i < count; i++) {
             View child = views[i];
@@ -356,7 +357,7 @@
             }
         }
 
-        views = mSortedHorizontalChildren;
+        views = mSortedVerticalChildren;
         count = views.length;
         for (int i = 0; i < count; i++) {
             View child = views[i];
@@ -766,14 +767,14 @@
     private View getRelatedView(int[] rules, int relation) {
         int id = rules[relation];
         if (id != 0) {
-            DependencyGraph.Node node = mGraph.mNodes.get(id);
+            DependencyGraph.Node node = mGraph.mKeyNodes.get(id);
             if (node == null) return null;
             View v = node.view;
 
             // Find the first non-GONE view up the chain
             while (v.getVisibility() == View.GONE) {
                 rules = ((LayoutParams) v.getLayoutParams()).getRules();
-                node = mGraph.mNodes.get((rules[relation]));
+                node = mGraph.mKeyNodes.get((rules[relation]));
                 if (node == null) return null;
                 v = node.view;
             }
@@ -1109,10 +1110,15 @@
 
     private static class DependencyGraph {
         /**
+         * List of all views in the graph.
+         */
+        private ArrayList<Node> mNodes = new ArrayList<Node>();
+
+        /**
          * List of nodes in the graph. Each node is identified by its
          * view id (see View#getId()).
          */
-        private SparseArray<Node> mNodes = new SparseArray<Node>();
+        private SparseArray<Node> mKeyNodes = new SparseArray<Node>();
 
         /**
          * Temporary data structure used to build the list of roots
@@ -1124,14 +1130,15 @@
          * Clears the graph.
          */
         void clear() {
-            final SparseArray<Node> nodes = mNodes;
+            final ArrayList<Node> nodes = mNodes;
             final int count = nodes.size();
 
             for (int i = 0; i < count; i++) {
-                nodes.valueAt(i).release();
+                nodes.get(i).release();
             }
             nodes.clear();
 
+            mKeyNodes.clear();
             mRoots.clear();
         }
 
@@ -1141,7 +1148,14 @@
          * @param view The view to be added as a node to the graph.
          */
         void add(View view) {
-            mNodes.put(view.getId(), Node.acquire(view));
+            final int id = view.getId();
+            final Node node = Node.acquire(view);
+
+            if (id != View.NO_ID) {
+                mKeyNodes.put(id, node);
+            }
+
+            mNodes.add(node);
         }
 
         /**
@@ -1192,20 +1206,21 @@
          * @return A list of node, each being a root of the graph
          */
         private LinkedList<Node> findRoots(int[] rulesFilter) {
-            final SparseArray<Node> nodes = mNodes;
+            final SparseArray<Node> keyNodes = mKeyNodes;
+            final ArrayList<Node> nodes = mNodes;
             final int count = nodes.size();
 
             // Find roots can be invoked several times, so make sure to clear
             // all dependents and dependencies before running the algorithm
             for (int i = 0; i < count; i++) {
-                final Node node = nodes.valueAt(i);
+                final Node node = nodes.get(i);
                 node.dependents.clear();
                 node.dependencies.clear();
             }
 
             // Builds up the dependents and dependencies for each node of the graph
             for (int i = 0; i < count; i++) {
-                final Node node = nodes.valueAt(i);
+                final Node node = nodes.get(i);
 
                 final LayoutParams layoutParams = (LayoutParams) node.view.getLayoutParams();
                 final int[] rules = layoutParams.mRules;
@@ -1217,11 +1232,14 @@
                     final int rule = rules[rulesFilter[j]];
                     if (rule > 0) {
                         // The node this node depends on
-                        final Node dependency = nodes.get(rule);
+                        final Node dependency = keyNodes.get(rule);
                         if (dependency == node) {
                             throw new IllegalStateException("A view cannot have a dependency" +
                                     " on itself");
                         }
+                        if (dependency == null) {
+                            continue;
+                        }
                         // Add the current node as a dependent
                         dependency.dependents.add(node);
                         // Add a dependency to the current node
@@ -1235,7 +1253,7 @@
 
             // Finds all the roots in the graph: all nodes with no dependencies
             for (int i = 0; i < count; i++) {
-                final Node node = nodes.valueAt(i);
+                final Node node = nodes.get(i);
                 if (node.dependencies.size() == 0) roots.add(node);
             }
 
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 945a325..c890b0f 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -496,7 +496,7 @@
                 const String8& field = fields[i];
                 if (strncmp(p, field.string(), field.length()) == 0) {
                     p += field.length();
-                    while (*p == ' ') p++;
+                    while (*p == ' ' || *p == '\t') p++;
                     char* num = p;
                     while (*p >= '0' && *p <= '9') p++;
                     skipToEol = *p != '\n';
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 25e31ee..de323b3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1052,23 +1052,25 @@
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;    
     
+    EGLSurface impl_draw = EGL_NO_SURFACE;
+    EGLSurface impl_read = EGL_NO_SURFACE;
     egl_context_t * const c = get_context(ctx);
     if (draw != EGL_NO_SURFACE) {
         egl_surface_t const * d = get_surface(draw);
         if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         if (d->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
-        draw = d->surface;
+        impl_draw = d->surface;
     }
     if (read != EGL_NO_SURFACE) {
         egl_surface_t const * r = get_surface(read);
         if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         if (r->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
-        read = r->surface;
+        impl_read = r->surface;
     }
     EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
-            dp->dpys[c->impl], draw, read, c->context);
+            dp->dpys[c->impl], impl_draw, impl_read, c->context);
 
     if (result == EGL_TRUE) {
         setGlThreadSpecific(c->cnx->hooks);
diff --git a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
index a12db8c..2ad218f 100644
--- a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 8358c5c..877fa6b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -25,8 +25,7 @@
  * The service that manages the L2TP-over-IPSec VPN connection.
  */
 class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
-    private static final String IPSEC_SERVICE = "racoon";
-    private static final String L2TP_SERVICE = "mtpd";
+    private static final String IPSEC_DAEMON = "racoon";
 
     @Override
     protected void connect(String serverIp, String username, String password)
@@ -34,7 +33,7 @@
         String hostIp = getHostIp();
 
         // IPSEC
-        AndroidServiceProxy ipsecService = startService(IPSEC_SERVICE);
+        AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON);
         ipsecService.sendCommand(
                 String.format("SETKEY %s %s", hostIp, serverIp));
         ipsecService.sendCommand(String.format("SET_CERTS %s %s %s %s",
@@ -42,11 +41,11 @@
                 getUserkeyPath()));
 
         // L2TP
-        AndroidServiceProxy l2tpService = startService(L2TP_SERVICE);
-        l2tpService.sendCommand2("l2tp", serverIp, "1701", "",
-                    "file", getPppOptionFilePath(),
-                    "name", username,
-                    "password", password);
+        L2tpIpsecProfile p = getProfile();
+        MtpdHelper.sendCommand(this, L2tpService.L2TP_DAEMON, serverIp,
+                L2tpService.L2TP_PORT,
+                (p.isSecretEnabled() ? p.getSecretString() : null),
+                username, password);
     }
 
     private String getCaCertPath() {
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
index 9aad7a1..9273f35 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -24,19 +24,15 @@
  * The service that manages the L2TP VPN connection.
  */
 class L2tpService extends VpnService<L2tpProfile> {
-    private static final String L2TP_SERVICE = "mtpd";
+    static final String L2TP_DAEMON = "l2tp";
+    static final String L2TP_PORT = "1701";
 
     @Override
     protected void connect(String serverIp, String username, String password)
             throws IOException {
-        String hostIp = getHostIp();
-
-        // L2TP
-        AndroidServiceProxy l2tpService = startService(L2TP_SERVICE);
-        l2tpService.sendCommand2("l2tp", serverIp, "1701", "",
-                    "file", getPppOptionFilePath(),
-                    "name", username,
-                    "password", password);
+        L2tpProfile p = getProfile();
+        MtpdHelper.sendCommand(this, L2TP_DAEMON, serverIp, L2TP_PORT,
+                (p.isSecretEnabled() ? p.getSecretString() : null),
+                username, password);
     }
-
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
new file mode 100644
index 0000000..6160900
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vpn;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A helper class for sending commands to the MTP daemon (mtpd).
+ */
+class MtpdHelper {
+    private static final String MTPD_SERVICE = "mtpd";
+    private static final String VPN_LINKNAME = "vpn";
+    private static final String PPP_ARGS_SEPARATOR = "";
+
+    static void sendCommand(VpnService<?> vpnService, String protocol,
+            String serverIp, String port, String secret, String username,
+            String password) throws IOException {
+        ArrayList<String> args = new ArrayList<String>();
+        args.addAll(Arrays.asList(protocol, serverIp, port));
+        if (secret != null) args.add(secret);
+        args.add(PPP_ARGS_SEPARATOR);
+        addPppArguments(vpnService, args, serverIp, username, password);
+
+        AndroidServiceProxy mtpd = vpnService.startService(MTPD_SERVICE);
+        mtpd.sendCommand2(args.toArray(new String[args.size()]));
+    }
+
+    private static void addPppArguments(VpnService<?> vpnService,
+            ArrayList<String> args, String serverIp, String username,
+            String password) throws IOException {
+        args.addAll(Arrays.asList(
+                "linkname", VPN_LINKNAME,
+                "name", username,
+                "password", password,
+                "ipparam", serverIp + "@" + vpnService.getGatewayIp(),
+                "refuse-eap", "nodefaultroute", "usepeerdns",
+                "idle", "1800",
+                "mtu", "1400",
+                "mru", "1400"));
+    }
+
+    private MtpdHelper() {
+    }
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
index f20d85f..f0bbc34 100644
--- a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/PptpService.java b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
new file mode 100644
index 0000000..01362a5
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vpn;
+
+import android.net.vpn.PptpProfile;
+
+import java.io.IOException;
+
+/**
+ * The service that manages the PPTP VPN connection.
+ */
+class PptpService extends VpnService<PptpProfile> {
+    static final String PPTP_DAEMON = "pptp";
+    static final String PPTP_PORT = "1723";
+    @Override
+    protected void connect(String serverIp, String username, String password)
+            throws IOException {
+        MtpdHelper.sendCommand(this, PPTP_DAEMON, serverIp, PPTP_PORT, null,
+                username, password);
+    }
+
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
index 14d7521..50fbf4b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index fdefe9c..44127ff 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -20,6 +20,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.net.NetworkUtils;
 import android.net.vpn.VpnManager;
 import android.net.vpn.VpnProfile;
 import android.net.vpn.VpnState;
@@ -31,8 +32,10 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 
 /**
@@ -153,16 +156,25 @@
     }
 
     /**
-     * Returns the IP of the specified host name.
+     * Returns the IP address of the specified host name.
      */
     protected String getIp(String hostName) throws IOException {
-        InetAddress iaddr = InetAddress.getByName(hostName);
-        byte[] aa = iaddr.getAddress();
-        StringBuilder sb = new StringBuilder().append(byteToInt(aa[0]));
-        for (int i = 1; i < aa.length; i++) {
-            sb.append(".").append(byteToInt(aa[i]));
+        return InetAddress.getByName(hostName).getHostAddress();
+    }
+
+    /**
+     * Returns the IP address of the default gateway.
+     */
+    protected String getGatewayIp() throws IOException {
+        Enumeration<NetworkInterface> ifces =
+                NetworkInterface.getNetworkInterfaces();
+        for (; ifces.hasMoreElements(); ) {
+            NetworkInterface ni = ifces.nextElement();
+            int gateway = NetworkUtils.getDefaultRoute(ni.getName());
+            if (gateway == 0) continue;
+            return toInetAddress(gateway).getHostAddress();
         }
-        return sb.toString();
+        throw new IOException("Default gateway is not available");
     }
 
     /**
@@ -170,7 +182,7 @@
      * connection is established.
      */
     protected String getConnectMonitorFile() {
-        return "/etc/ppp/ip-up";
+        return "/etc/ppp/ip-up-vpn";
     }
 
     /**
@@ -461,12 +473,18 @@
     }
 
     private String reallyGetHostIp() throws IOException {
-        Socket s = new Socket();
-        s.connect(new InetSocketAddress("www.google.com", 80), DNS_TIMEOUT);
-        String ipAddress = s.getLocalAddress().getHostAddress();
-        Log.d(TAG, "Host IP: " + ipAddress);
-        s.close();
-        return ipAddress;
+        Enumeration<NetworkInterface> ifces =
+                NetworkInterface.getNetworkInterfaces();
+        for (; ifces.hasMoreElements(); ) {
+            NetworkInterface ni = ifces.nextElement();
+            int gateway = NetworkUtils.getDefaultRoute(ni.getName());
+            if (gateway == 0) continue;
+            Enumeration<InetAddress> addrs = ni.getInetAddresses();
+            for (; addrs.hasMoreElements(); ) {
+                return addrs.nextElement().getHostAddress();
+            }
+        }
+        throw new IOException("Host IP is not available");
     }
 
     private String getProfileSubpath(String subpath) throws IOException {
@@ -496,8 +514,13 @@
         return ((message == null) || (message.length() == 0));
     }
 
-    private static int byteToInt(byte b) {
-        return ((int) b) & 0x0FF;
+    private InetAddress toInetAddress(int addr) throws IOException {
+        byte[] aa = new byte[4];
+        for (int i= 0; i < aa.length; i++) {
+            aa[i] = (byte) (addr & 0x0FF);
+            addr >>= 8;
+        }
+        return InetAddress.getByAddress(aa);
     }
 
     private class ServiceHelper implements ProcessProxy.Callback {
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 7195ea61..63fc858 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index efa6179..a6639de 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -164,8 +164,7 @@
         // Set up our transport options and initialize the default transport
         // TODO: Have transports register themselves somehow?
         // TODO: Don't create transports that we don't need to?
-        mTransportId = BackupManager.TRANSPORT_LOCAL;
-        //mTransportId = BackupManager.TRANSPORT_GOOGLE;
+        mTransportId = BackupManager.TRANSPORT_GOOGLE;
         mLocalTransport = new LocalTransport(context);  // This is actually pretty cheap
         mGoogleTransport = null;
 
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 9f780c9..4db3e5b 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1365,7 +1365,6 @@
         RILRequest rr
                 = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result);
 
-        rr.mp.writeInt(2);
         rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass
         // cause code according to X.S004-550E
         rr.mp.writeInt(cause);
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index a3016fa..62a5d65 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -289,7 +289,13 @@
             sms = (SmsMessage) ar.result;
             try {
                 if (mStorageAvailable) {
-                    dispatchMessage(sms.mWrappedSmsMessage);
+                    int result = dispatchMessage(sms.mWrappedSmsMessage);
+                    if (result != Activity.RESULT_OK) {
+                        // RESULT_OK means that message was broadcast for app(s) to handle.
+                        // Any other result, we should ack here.
+                        boolean handled = (result == Intents.RESULT_SMS_HANDLED);
+                        acknowledgeLastIncomingSms(handled, result, null);
+                    }
                 } else {
                     acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_OUT_OF_MEMORY, null);
                 }
@@ -469,8 +475,11 @@
      * Dispatches an incoming SMS messages.
      *
      * @param sms the incoming message from the phone
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected abstract void dispatchMessage(SmsMessageBase sms);
+    protected abstract int dispatchMessage(SmsMessageBase sms);
 
 
     /**
@@ -478,8 +487,11 @@
      * the part is stored for later processing.
      *
      * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null.
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected void processMessagePart(SmsMessageBase sms,
+    protected int processMessagePart(SmsMessageBase sms,
             SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) {
 
         // Lookup all other related parts
@@ -506,8 +518,7 @@
                     values.put("destination_port", portAddrs.destPort);
                 }
                 mResolver.insert(mRawUri, values);
-                acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
 
             // All the parts are in place, deal with them
@@ -529,8 +540,7 @@
         } catch (SQLException e) {
             Log.e(TAG, "Can't access multipart SMS database", e);
             // TODO:  Would OUT_OF_MEMORY be more appropriate?
-            acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -555,7 +565,7 @@
                     output.write(data, 0, data.length);
                 }
                 // Handle the PUSH
-                mWapPush.dispatchWapPdu(output.toByteArray());
+                return mWapPush.dispatchWapPdu(output.toByteArray());
             } else {
                 // The messages were sent to a port, so concoct a URI for it
                 dispatchPortAddressedPdus(pdus, portAddrs.destPort);
@@ -564,6 +574,7 @@
             // The messages were not sent to a port
             dispatchPdus(pdus);
         }
+        return Activity.RESULT_OK;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index a9aacda..99709406 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.telephony;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.util.Config;
 import android.util.Log;
@@ -51,8 +53,11 @@
      * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
      *
      * @param pdu The WAP PDU, made up of one or more SMS PDUs
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    public void dispatchWapPdu(byte[] pdu) {
+    public int dispatchWapPdu(byte[] pdu) {
 
         if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
 
@@ -64,7 +69,7 @@
         if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
                 (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
-            return;
+            return Intents.RESULT_SMS_HANDLED;
         }
 
         pduDecoder = new WspTypeDecoder(pdu);
@@ -77,7 +82,7 @@
          */
         if (pduDecoder.decodeUintvarInteger(index) == false) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         headerLength = (int)pduDecoder.getValue32();
         index += pduDecoder.getDecodedDataLength();
@@ -98,7 +103,7 @@
          */
         if (pduDecoder.decodeContentType(index) == false) {
             if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         int binaryContentType;
         String mimeType = pduDecoder.getValueString();
@@ -128,7 +133,7 @@
                         Log.w(LOG_TAG,
                                 "Received PDU. Unsupported Content-Type = " + binaryContentType);
                     }
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
         } else {
             if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
@@ -145,7 +150,7 @@
                 binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
             } else {
                 if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
         }
         index += pduDecoder.getDecodedDataLength();
@@ -167,6 +172,7 @@
         if (dispatchedByApplication == false) {
             dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex);
         }
+        return Activity.RESULT_OK;
     }
 
     private void dispatchWapPdu_default(
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 8a0070d..2d43e0de 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -25,6 +25,7 @@
 import android.database.SQLException;
 import android.os.AsyncResult;
 import android.os.Message;
+import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.preference.PreferenceManager;
 import android.util.Config;
@@ -66,17 +67,12 @@
         Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
     }
 
-    /**
-     * Dispatches an incoming SMS messages.
-     *
-     * @param smsb the incoming message from the phone
-     */
-    protected void dispatchMessage(SmsMessageBase smsb) {
+    /** {@inheritDoc} */
+    protected int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
-        // TODO: Should NAK this.
         if (smsb == null) {
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
 
         // Decode BD stream and set sms variables.
@@ -92,11 +88,13 @@
             handled = true;
         }
 
-        if (handled) return;
+        if (handled) {
+            return Intents.RESULT_SMS_HANDLED;
+        }
 
         if (SmsEnvelope.TELESERVICE_WAP == teleService){
-            processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress());
-            return;
+            return processCdmaWapPdu(sms.getUserData(), sms.messageRef,
+                    sms.getOriginatingAddress());
         } else if (SmsEnvelope.TELESERVICE_VMN == teleService) {
             // handling Voicemail
             int voicemailCount = sms.getNumOfVoicemails();
@@ -108,7 +106,7 @@
             editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
             editor.commit();
             ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
-            return;
+            return Intents.RESULT_SMS_HANDLED;
         }
 
         /**
@@ -138,17 +136,19 @@
             if (smsHeader != null && smsHeader.portAddrs != null) {
                 if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
                     // GSM-style WAP indication
-                    mWapPush.dispatchWapPdu(sms.getUserData());
+                    return mWapPush.dispatchWapPdu(sms.getUserData());
+                } else {
+                    // The message was sent to a port, so concoct a URI for it.
+                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
                 }
-                // The message was sent to a port, so concoct a URI for it.
-                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
                 // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
+            return Activity.RESULT_OK;
         } else {
             // Process the message part.
-            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
+            return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
@@ -158,8 +158,11 @@
      * WDP segments are gathered until a datagram completes and gets dispatched.
      *
      * @param pdu The WAP-WDP PDU segment
+     * @return a result code from {@link Telephony.Sms.Intents}, or
+     *         {@link Activity#RESULT_OK} if the message has been broadcast
+     *         to applications
      */
-    protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
+    protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
         int segment;
         int totalSegments;
         int index = 0;
@@ -171,7 +174,7 @@
         msgType = pdu[index++];
         if (msgType != 0){
             Log.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
-            return;
+            return Intents.RESULT_SMS_HANDLED;
         }
         totalSegments = pdu[index++]; // >=1
         segment = pdu[index++]; // >=0
@@ -210,7 +213,7 @@
 
                 mResolver.insert(mRawUri, values);
 
-                return;
+                return Intents.RESULT_SMS_HANDLED;
             }
 
             // All the parts are in place, deal with them
@@ -230,7 +233,7 @@
             mResolver.delete(mRawUri, where.toString(), whereArgs);
         } catch (SQLException e) {
             Log.e(TAG, "Can't access multipart SMS database", e);
-            return;  // TODO: NACK the message or something, don't just discard.
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         } finally {
             if (cursor != null) cursor.close();
         }
@@ -250,15 +253,14 @@
         switch (destinationPort) {
         case SmsHeader.PORT_WAP_PUSH:
             // Handle the PUSH
-            mWapPush.dispatchWapPdu(datagram);
-            break;
+            return mWapPush.dispatchWapPdu(datagram);
 
         default:{
             pdus = new byte[1][];
             pdus[0] = datagram;
             // The messages were sent to any other WAP port
             dispatchPortAddressedPdus(pdus, destinationPort);
-            break;
+            return Activity.RESULT_OK;
         }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index f87392a..2770ddc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -78,24 +78,16 @@
                 }
             }
         }
-
-        if (mCm != null) {
-            mCm.acknowledgeLastIncomingGsmSms(true, Intents.RESULT_SMS_HANDLED, null);
-        }
+        acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
     }
 
 
-    /**
-     * Dispatches an incoming SMS messages.
-     *
-     * @param sms the incoming message from the phone
-     */
-    protected void dispatchMessage(SmsMessageBase smsb) {
+    /** {@inheritDoc} */
+    protected int dispatchMessage(SmsMessageBase smsb) {
 
         // If sms is null, means there was a parsing error.
-        // TODO: Should NAK this.
         if (smsb == null) {
-            return;
+            return Intents.RESULT_SMS_GENERIC_ERROR;
         }
         SmsMessage sms = (SmsMessage) smsb;
         boolean handled = false;
@@ -115,7 +107,9 @@
             }
         }
 
-        if (handled) return;
+        if (handled) {
+            return Intents.RESULT_SMS_HANDLED;
+        }
 
         SmsHeader smsHeader = sms.getUserDataHeader();
          // See if message is partial or port addressed.
@@ -126,17 +120,19 @@
 
             if (smsHeader != null && smsHeader.portAddrs != null) {
                 if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
-                    mWapPush.dispatchWapPdu(sms.getUserData());
+                    return mWapPush.dispatchWapPdu(sms.getUserData());
+                } else {
+                    // The message was sent to a port, so concoct a URI for it.
+                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
                 }
-                // The message was sent to a port, so concoct a URI for it.
-                dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
             } else {
                 // Normal short and non-port-addressed message, dispatch it.
                 dispatchPdus(pdus);
             }
+            return Activity.RESULT_OK;
         } else {
             // Process the message part.
-            processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
+            return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
         }
     }
 
diff --git a/vpn/java/android/net/vpn/IVpnService.aidl b/vpn/java/android/net/vpn/IVpnService.aidl
index 0e658df..fedccb0 100644
--- a/vpn/java/android/net/vpn/IVpnService.aidl
+++ b/vpn/java/android/net/vpn/IVpnService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/vpn/java/android/net/vpn/L2tpIpsecProfile.java b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
index 181619d..4ae2dec 100644
--- a/vpn/java/android/net/vpn/L2tpIpsecProfile.java
+++ b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -19,15 +19,14 @@
 import android.os.Parcel;
 
 /**
- * The profile for L2TP-over-IPSec type of VPN.
+ * The profile for certificate-based L2TP-over-IPSec type of VPN.
  * {@hide}
  */
-public class L2tpIpsecProfile extends VpnProfile {
+public class L2tpIpsecProfile extends L2tpProfile {
     private static final long serialVersionUID = 1L;
 
     private String mUserCertificate;
     private String mCaCertificate;
-    private String mUserkey;
 
     @Override
     public VpnType getType() {
@@ -50,20 +49,11 @@
         return mUserCertificate;
     }
 
-    public void setUserkey(String name) {
-        mUserkey = name;
-    }
-
-    public String getUserkey() {
-        return mUserkey;
-    }
-
     @Override
     protected void readFromParcel(Parcel in) {
         super.readFromParcel(in);
         mCaCertificate = in.readString();
         mUserCertificate = in.readString();
-        mUserkey = in.readString();
     }
 
     @Override
@@ -71,6 +61,5 @@
         super.writeToParcel(parcel, flags);
         parcel.writeString(mCaCertificate);
         parcel.writeString(mUserCertificate);
-        parcel.writeString(mUserkey);
     }
 }
diff --git a/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
new file mode 100644
index 0000000..7a03018
--- /dev/null
+++ b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for pre-shared-key-based L2TP-over-IPSec type of VPN.
+ * {@hide}
+ */
+public class L2tpIpsecPskProfile extends L2tpProfile {
+    private static final long serialVersionUID = 1L;
+
+    private String mPresharedKey;
+
+    @Override
+    public VpnType getType() {
+        return VpnType.L2TP_IPSEC_PSK;
+    }
+
+    public void setPresharedKey(String key) {
+        mPresharedKey = key;
+    }
+
+    public String getPresharedKey() {
+        return mPresharedKey;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mPresharedKey = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeString(mPresharedKey);
+    }
+}
diff --git a/vpn/java/android/net/vpn/L2tpProfile.java b/vpn/java/android/net/vpn/L2tpProfile.java
index 59d4981..dbba0c5 100644
--- a/vpn/java/android/net/vpn/L2tpProfile.java
+++ b/vpn/java/android/net/vpn/L2tpProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -16,6 +16,8 @@
 
 package android.net.vpn;
 
+import android.os.Parcel;
+
 /**
  * The profile for L2TP type of VPN.
  * {@hide}
@@ -23,8 +25,44 @@
 public class L2tpProfile extends VpnProfile {
     private static final long serialVersionUID = 1L;
 
+    private boolean mSecret;
+    private String mSecretString;
+
     @Override
     public VpnType getType() {
         return VpnType.L2TP;
     }
+
+    /**
+     * Enables/disables the secret for authenticating tunnel connection.
+     */
+    public void setSecretEnabled(boolean enabled) {
+        mSecret = enabled;
+    }
+
+    public boolean isSecretEnabled() {
+        return mSecret;
+    }
+
+    public void setSecretString(String secret) {
+        mSecretString = secret;
+    }
+
+    public String getSecretString() {
+        return mSecretString;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mSecret = in.readInt() > 0;
+        mSecretString = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeInt(mSecret ? 1 : 0);
+        parcel.writeString(mSecretString);
+    }
 }
diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java
new file mode 100644
index 0000000..c68bb71
--- /dev/null
+++ b/vpn/java/android/net/vpn/PptpProfile.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+/**
+ * The profile for PPTP type of VPN.
+ * {@hide}
+ */
+public class PptpProfile extends VpnProfile {
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public VpnType getType() {
+        return VpnType.PPTP;
+    }
+}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index 98795bd..dc70b26 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/vpn/java/android/net/vpn/VpnProfile.aidl b/vpn/java/android/net/vpn/VpnProfile.aidl
index ad34bfc..edeaef0 100644
--- a/vpn/java/android/net/vpn/VpnProfile.aidl
+++ b/vpn/java/android/net/vpn/VpnProfile.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/vpn/java/android/net/vpn/VpnProfile.java b/vpn/java/android/net/vpn/VpnProfile.java
index 9e24da4..bd6c809 100644
--- a/vpn/java/android/net/vpn/VpnProfile.java
+++ b/vpn/java/android/net/vpn/VpnProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/vpn/java/android/net/vpn/VpnState.java b/vpn/java/android/net/vpn/VpnState.java
index 977d938..ebd9364 100644
--- a/vpn/java/android/net/vpn/VpnState.java
+++ b/vpn/java/android/net/vpn/VpnState.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index 91b0ea2..c7df943 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, The Android Open Source Project
+ * Copyright (C) 2009, 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.
@@ -21,14 +21,21 @@
  * {@hide}
  */
 public enum VpnType {
-    L2TP_IPSEC("L2TP/IPSec", L2tpIpsecProfile.class),
-    L2TP("L2TP", L2tpProfile.class);
+    PPTP("PPTP", "", PptpProfile.class),
+    L2TP("L2TP", "", L2tpProfile.class),
+    L2TP_IPSEC_PSK("L2TP/IPSec PSK", "Pre-shared key based L2TP/IPSec VPN",
+            L2tpIpsecPskProfile.class),
+    L2TP_IPSEC("L2TP/IPSec CRT", "Certificate based L2TP/IPSec VPN",
+            L2tpIpsecProfile.class);
 
     private String mDisplayName;
+    private String mDescription;
     private Class<? extends VpnProfile> mClass;
 
-    VpnType(String displayName, Class<? extends VpnProfile> klass) {
+    VpnType(String displayName, String description,
+            Class<? extends VpnProfile> klass) {
         mDisplayName = displayName;
+        mDescription = description;
         mClass = klass;
     }
 
@@ -36,6 +43,10 @@
         return mDisplayName;
     }
 
+    public String getDescription() {
+        return mDescription;
+    }
+
     public Class<? extends VpnProfile> getProfileClass() {
         return mClass;
     }