Merge "Add constant to android-common for voice search's EXTRA_CALLING_PACKAGE, and use it from SearchDialog."
diff --git a/Android.mk b/Android.mk
index 0911712..a48ef45 100644
--- a/Android.mk
+++ b/Android.mk
@@ -116,13 +116,11 @@
 	core/java/android/hardware/ISensorService.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
-	core/java/android/os/ICheckinService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/storage/IMountService.aidl \
 	core/java/android/os/storage/IMountServiceListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/INetStatService.aidl \
-	core/java/android/os/IParentalControlCallback.aidl \
 	core/java/android/os/IPermissionController.aidl \
 	core/java/android/os/IPowerManager.aidl \
     core/java/android/os/IRemoteCallback.aidl \
diff --git a/api/current.xml b/api/current.xml
index be14731..9c663fe 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -85760,6 +85760,509 @@
 >
 </field>
 </class>
+<class name="Downloads"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="isStatusError"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="status" type="int">
+</parameter>
+</method>
+<method name="isStatusSuccess"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="status" type="int">
+</parameter>
+</method>
+<field name="ACTION_DOWNLOAD_COMPLETED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.DOWNLOAD_COMPLETED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_NOTIFICATION_EXTRAS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;notificationextras&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DOWNLOAD_DESTINATION_CACHE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DOWNLOAD_DESTINATION_CACHE_PURGEABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DOWNLOAD_DESTINATION_EXTERNAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DOWNLOAD_ID_INVALID"
+ type="long"
+ transient="false"
+ volatile="false"
+ value="-1L"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_DEVICE_NOT_FOUND_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="499"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_INSUFFICIENT_SPACE_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="498"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_NOT_ACCEPTABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="406"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_PENDING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="190"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_RUNNING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_SUCCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="200"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_UNHANDLED_REDIRECT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="493"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_UNKNOWN_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="491"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Downloads.ById"
+ extends="android.net.Downloads.DownloadBase"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="deleteDownload"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="downloadId" type="long">
+</parameter>
+</method>
+<method name="getMimeTypeForId"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="downloadId" type="long">
+</parameter>
+</method>
+<method name="getStatus"
+ return="android.net.Downloads.StatusInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="downloadId" type="long">
+</parameter>
+</method>
+<method name="openDownload"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="downloadId" type="long">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+</method>
+<method name="openDownloadStream"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="downloadId" type="long">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="Downloads.ByUri"
+ extends="android.net.Downloads.DownloadBase"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getProgressColumnCurrentBytes"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProgressColumnId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProgressColumnTotalBytes"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProgressCursor"
+ return="android.database.Cursor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="id" type="long">
+</parameter>
+</method>
+<method name="getStatus"
+ return="android.net.Downloads.StatusInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="redownload_threshold" type="long">
+</parameter>
+</method>
+<method name="removeAllDownloadsByPackage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="notification_package" type="java.lang.String">
+</parameter>
+<parameter name="notification_class" type="java.lang.String">
+</parameter>
+</method>
+</class>
+<class name="Downloads.DownloadBase"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="private"
+>
+<method name="startDownloadByUri"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="cookieData" type="java.lang.String">
+</parameter>
+<parameter name="showDownload" type="boolean">
+</parameter>
+<parameter name="downloadDestination" type="int">
+</parameter>
+<parameter name="allowRoaming" type="boolean">
+</parameter>
+<parameter name="skipIntegrityCheck" type="boolean">
+</parameter>
+<parameter name="title" type="java.lang.String">
+</parameter>
+<parameter name="notification_package" type="java.lang.String">
+</parameter>
+<parameter name="notification_class" type="java.lang.String">
+</parameter>
+<parameter name="notification_extras" type="java.lang.String">
+</parameter>
+</method>
+</class>
+<class name="Downloads.StatusInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Downloads.StatusInfo"
+ type="android.net.Downloads.StatusInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="isComplete"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isSuccessful"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="bytesSoFar"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="completed"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="filename"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="id"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="statusCode"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="LocalServerSocket"
  extends="java.lang.Object"
  abstract="false"
@@ -86840,7 +87343,7 @@
 </parameter>
 </method>
 <method name="getDefault"
- return="javax.net.SocketFactory"
+ return="javax.net.ssl.SSLSocketFactory"
  abstract="false"
  native="false"
  synchronized="false"
@@ -86880,6 +87383,21 @@
 <parameter name="cache" type="android.net.SSLSessionCache">
 </parameter>
 </method>
+<method name="getInsecure"
+ return="javax.net.ssl.SSLSocketFactory"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+<parameter name="cache" type="android.net.SSLSessionCache">
+</parameter>
+</method>
 <method name="getSupportedCipherSuites"
  return="java.lang.String[]"
  abstract="false"
@@ -147334,6 +147852,38 @@
 <parameter name="count" type="int">
 </parameter>
 </method>
+<method name="getEastAsianWidth"
+ return="int"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="input" type="char">
+</parameter>
+</method>
+<method name="getEastAsianWidths"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="char[]">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="count" type="int">
+</parameter>
+<parameter name="dest" type="byte[]">
+</parameter>
+</method>
 <method name="getMirror"
  return="char"
  abstract="false"
@@ -147364,6 +147914,72 @@
 <parameter name="count" type="int">
 </parameter>
 </method>
+<field name="EAST_ASIAN_WIDTH_AMBIGUOUS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EAST_ASIAN_WIDTH_FULL_WIDTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EAST_ASIAN_WIDTH_HALF_WIDTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EAST_ASIAN_WIDTH_NARROW"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EAST_ASIAN_WIDTH_NEUTRAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EAST_ASIAN_WIDTH_WIDE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Annotation"
  extends="java.lang.Object"
@@ -163707,7 +164323,7 @@
  visibility="public"
 >
 </field>
-<field name="WEB_SAFE"
+<field name="URL_SAFE"
  type="int"
  transient="false"
  volatile="false"
@@ -168648,6 +169264,28 @@
  visibility="public"
 >
 </method>
+<method name="getActionIndex"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getActionMasked"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDeviceId"
  return="int"
  abstract="false"
@@ -169268,7 +169906,7 @@
  value="5"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169279,7 +169917,7 @@
  value="6"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169290,7 +169928,7 @@
  value="261"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169301,7 +169939,7 @@
  value="262"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169312,7 +169950,7 @@
  value="517"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169323,7 +169961,7 @@
  value="518"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169345,7 +169983,7 @@
  value="65280"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -169356,6 +169994,28 @@
  value="8"
  static="true"
  final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_INDEX_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_INDEX_SHIFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
  deprecated="not deprecated"
  visibility="public"
 >
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 68373cb..ff16c6e 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -600,7 +600,7 @@
             } else if (opt.equals("-t")) {
                 installFlags |= PackageManager.INSTALL_ALLOW_TEST;
             } else if (opt.equals("-s")) {
-                installFlags |= PackageManager.INSTALL_ON_SDCARD;
+                installFlags |= PackageManager.INSTALL_EXTERNAL;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
diff --git a/common/java/com/android/common/Base64.java b/common/java/com/android/common/Base64.java
deleted file mode 100644
index d65e24e..0000000
--- a/common/java/com/android/common/Base64.java
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.common;
-
-/**
- * Utilities for encoding and decoding the Base64 encoding.  See RFCs
- * 2045 and 3548.
- */
-public class Base64 {
-    /**
-     * Default values for encoder/decoder flags.
-     */
-    public static final int DEFAULT = 0;
-
-    /**
-     * Encoder flag bit to indicate you want the padding '='
-     * characters at the end (if any) to be omitted.
-     */
-    public static final int NO_PADDING = 1;
-
-    /**
-     * Encoder flag bit to indicate you want all line terminators to
-     * be omitted (ie, the output will be on one long line).
-     */
-    public static final int NO_WRAP = 2;
-
-    /**
-     * Encoder flag bit to indicate you want lines to be ended with
-     * CRLF instead of just LF.
-     */
-    public static final int CRLF = 4;
-
-    /**
-     * Encoder/decoder flag bit to indicate using the "web safe"
-     * variant of Base64 (see RFC 3548 section 4) where '-' and '_'
-     * are used in place of '+' and '/'.
-     */
-    public static final int WEB_SAFE = 8;
-
-    /**
-     * Flag to pass to Base64OutputStream to indicate that it should
-     * not close the output stream it is wrapping when it itself is
-     * closed.
-     */
-    public static final int NO_CLOSE = 16;
-
-    //  --------------------------------------------------------
-    //  decoding
-    //  --------------------------------------------------------
-
-    /**
-     * Lookup table for turning bytes into their position in the
-     * Base64 alphabet.
-     */
-    private static final int DECODE[] = {
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
-        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    };
-
-    /**
-     * Decode lookup table for the "web safe" variant (RFC 3548
-     * sec. 4) where - and _ replace + and /.
-     */
-    private static final int DECODE_WEBSAFE[] = {
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
-        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
-        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    };
-
-    /** Non-data values in the DECODE arrays. */
-    private static final int SKIP = -1;
-    private static final int EQUALS = -2;
-
-    /**
-     * Decode the Base64-encoded data in input and return the data in
-     * a new byte array.
-     *
-     * The padding '=' characters at the end are considered optional, but
-     * if any are present, there must be the correct number of them.
-     *
-     * @param input the input String to decode, which is converted to
-     *               bytes using the default charset
-     * @param flags  controls certain features of the decoded output.
-     *               Pass {@code DEFAULT} to decode standard Base64.
-     *
-     * @throws IllegalArgumentException if the input contains
-     * incorrect padding
-     */
-    public static byte[] decode(String str, int flags) {
-        return decode(str.getBytes(), flags);
-    }
-
-    /**
-     * Decode the Base64-encoded data in input and return the data in
-     * a new byte array.
-     *
-     * The padding '=' characters at the end are considered optional, but
-     * if any are present, there must be the correct number of them.
-     *
-     * @param input the input array to decode
-     * @param flags  controls certain features of the decoded output.
-     *               Pass {@code DEFAULT} to decode standard Base64.
-     *
-     * @throws IllegalArgumentException if the input contains
-     * incorrect padding
-     */
-    public static byte[] decode(byte[] input, int flags) {
-        return decode(input, 0, input.length, flags);
-    }
-
-    /**
-     * Decode the Base64-encoded data in input and return the data in
-     * a new byte array.
-     *
-     * The padding '=' characters at the end are considered optional, but
-     * if any are present, there must be the correct number of them.
-     *
-     * @param input  the data to decode
-     * @param offset the position within the input array at which to start
-     * @param len    the number of bytes of input to decode
-     * @param flags  controls certain features of the decoded output.
-     *               Pass {@code DEFAULT} to decode standard Base64.
-     *
-     * @throws IllegalArgumentException if the input contains
-     * incorrect padding
-     */
-    public static byte[] decode(byte[] input, int offset, int len, int flags) {
-        // Allocate space for the most data the input could represent.
-        // (It could contain less if it contains whitespace, etc.)
-        DecoderState state = new DecoderState(flags, new byte[len*3/4]);
-
-        if (!decodeInternal(input, offset, len, state, true)) {
-            throw new IllegalArgumentException("bad base-64");
-        }
-
-        // Maybe we got lucky and allocated exactly enough output space.
-        if (state.op == state.output.length) {
-            return state.output;
-        }
-
-        // Need to shorten the array, so allocate a new one of the
-        // right size and copy.
-        byte[] temp = new byte[state.op];
-        System.arraycopy(state.output, 0, temp, 0, state.op);
-        return temp;
-    }
-
-    /* package */ static class DecoderState {
-        public byte[] output;
-        public int op;
-
-        public int state;   // state number (0 to 6)
-        public int value;
-
-        final public int[] alphabet;
-
-        public DecoderState(int flags, byte[] output) {
-            this.output = output;
-
-            alphabet = ((flags & WEB_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
-            state = 0;
-            value = 0;
-        }
-    }
-
-    /**
-     * Decode another block of input data.
-     *
-     * @param dstate a DecoderState object whose (caller-provided)
-     *        output array is big enough to hold all the decoded data.
-     *        On return, dstate.op will be set to the length of the
-     *        decoded data.
-     * @param finish true if this is the final call to decodeInternal
-     *        with the given DecoderState object.  Will finalize the
-     *        decoder state and include any final bytes in the output.
-     *
-     * @return true if the state machine is still healthy.  false if
-     *         bad base-64 data has been detected in the input stream.
-     */
-
-    /* package */ static boolean decodeInternal(
-        byte[] input, int offset, int len, final DecoderState dstate, boolean finish) {
-        if (dstate.state == 6) return false;
-
-        int state = dstate.state;
-        int value = dstate.value;
-        final int[] decode = dstate.alphabet;
-        final byte[] output = dstate.output;
-        int op = 0;
-
-        int p = offset;
-        len += offset;
-
-        while (p < len) {
-
-            // Try the fast path:  we're starting a new tuple and the
-            // next four bytes of the input stream are all data
-            // bytes.  This corresponds to going through states
-            // 0-1-2-3-0.  We expect to use this method for most of
-            // the data.
-            //
-            // If any of the next four bytes of input are non-data
-            // (whitespace, etc.), value will end up negative.  (All
-            // the non-data values in decode are small negative
-            // numbers, so shifting any of them up and or'ing them
-            // together will result in a value with its top bit set.)
-            //
-            // You can remove this whole block and the output should
-            // be the same, just slower.
-            if (state == 0 && p+4 <= len &&
-                (value = ((decode[input[p] & 0xff] << 18) |
-                          (decode[input[p+1] & 0xff] << 12) |
-                          (decode[input[p+2] & 0xff] << 6) |
-                          (decode[input[p+3] & 0xff]))) >= 0) {
-                output[op+2] = (byte) value;
-                output[op+1] = (byte) (value >> 8);
-                output[op] = (byte) (value >> 16);
-                op += 3;
-                p += 4;
-                continue;
-            }
-
-            // The fast path isn't available -- either we've read a
-            // partial tuple, or the next four input bytes aren't all
-            // data, or whatever.  Fall back to the slower state
-            // machine implementation.
-            //
-            // States 0-3 are reading through the next input tuple.
-            // State 4 is having read one '=' and expecting exactly
-            // one more.
-            // State 5 is expecting no more data or padding characters
-            // in the input.
-            // State 6 is the error state; an error has been detected
-            // in the input and no future input can "fix" it.
-
-            int d = decode[input[p++] & 0xff];
-
-            switch (state) {
-                case 0:
-                    if (d >= 0) {
-                        value = d;
-                        ++state;
-                    } else if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-
-                case 1:
-                    if (d >= 0) {
-                        value = (value << 6) | d;
-                        ++state;
-                    } else if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-
-                case 2:
-                    if (d >= 0) {
-                        value = (value << 6) | d;
-                        ++state;
-                    } else if (d == EQUALS) {
-                        // Emit the last (partial) output tuple;
-                        // expect exactly one more padding character.
-                        output[op++] = (byte) (value >> 4);
-                        state = 4;
-                    } else if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-
-                case 3:
-                    if (d >= 0) {
-                        // Emit the output triple and return to state 0.
-                        value = (value << 6) | d;
-                        output[op+2] = (byte) value;
-                        output[op+1] = (byte) (value >> 8);
-                        output[op] = (byte) (value >> 16);
-                        op += 3;
-                        state = 0;
-                    } else if (d == EQUALS) {
-                        // Emit the last (partial) output tuple;
-                        // expect no further data or padding characters.
-                        output[op+1] = (byte) (value >> 2);
-                        output[op] = (byte) (value >> 10);
-                        op += 2;
-                        state = 5;
-                    } else if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-
-                case 4:
-                    if (d == EQUALS) {
-                        ++state;
-                    } else if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-
-                case 5:
-                    if (d != SKIP) {
-                        dstate.state = 6;
-                        return false;
-                    }
-                    break;
-            }
-        }
-
-        if (!finish) {
-            // We're out of input, but a future call could provide
-            // more.  Return the output we've produced on this call
-            // and save the current state of the state machine.
-            dstate.state = state;
-            dstate.value = value;
-            dstate.op = op;
-            return true;
-        }
-
-        // Done reading input.  Now figure out where we are left in
-        // the state machine and finish up.
-
-        switch (state) {
-            case 0:
-                // Output length is a multiple of three.  Fine.
-                break;
-            case 1:
-                // Read one extra input byte, which isn't enough to
-                // make another output byte.  Illegal.
-                dstate.state = 6;
-                return false;
-            case 2:
-                // Read two extra input bytes, enough to emit 1 more
-                // output byte.  Fine.
-                output[op++] = (byte) (value >> 4);
-                break;
-            case 3:
-                // Read three extra input bytes, enough to emit 2 more
-                // output bytes.  Fine.
-                output[op+1] = (byte) (value >> 2);
-                output[op] = (byte) (value >> 10);
-                op += 2;
-                break;
-            case 4:
-                // Read one padding '=' when we expected 2.  Illegal.
-                dstate.state = 6;
-                return false;
-            case 5:
-                // Read all the padding '='s we expected and no more.
-                // Fine.
-                break;
-        }
-
-        dstate.op = op;
-        return true;
-    }
-
-    //  --------------------------------------------------------
-    //  encoding
-    //  --------------------------------------------------------
-
-    /**
-     * Emit a new line every this many output tuples.  Corresponds to
-     * a 76-character line length (the maximum allowable according to
-     * RFC 2045).
-     */
-    private static final int LINE_GROUPS = 19;
-
-    /**
-     * Lookup table for turning Base64 alphabet positions (6 bits)
-     * into output bytes.
-     */
-    private static final byte ENCODE[] = {
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-        'w', 'x', 'y', 'z', '0', '1', '2', '3',
-        '4', '5', '6', '7', '8', '9', '+', '/',
-    };
-
-    /**
-     * Lookup table for turning Base64 alphabet positions (6 bits)
-     * into output bytes.
-     */
-    private static final byte ENCODE_WEBSAFE[] = {
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-        'w', 'x', 'y', 'z', '0', '1', '2', '3',
-        '4', '5', '6', '7', '8', '9', '-', '_',
-    };
-
-    /**
-     * Base64-encode the given data and return a newly allocated
-     * String with the result.
-     *
-     * @param input  the data to encode
-     * @param flags  controls certain features of the encoded output.
-     *               Passing {@code DEFAULT} results in output that
-     *               adheres to RFC 2045.
-     */
-    public static String encodeToString(byte[] input, int flags) {
-        return new String(encode(input, flags));
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated
-     * String with the result.
-     *
-     * @param input  the data to encode
-     * @param offset the position within the input array at which to
-     *               start
-     * @param len    the number of bytes of input to encode
-     * @param flags  controls certain features of the encoded output.
-     *               Passing {@code DEFAULT} results in output that
-     *               adheres to RFC 2045.
-     */
-    public static String encodeToString(byte[] input, int offset, int len, int flags) {
-        return new String(encode(input, offset, len, flags));
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated
-     * byte[] with the result.
-     *
-     * @param input  the data to encode
-     * @param flags  controls certain features of the encoded output.
-     *               Passing {@code DEFAULT} results in output that
-     *               adheres to RFC 2045.
-     */
-    public static byte[] encode(byte[] input, int flags) {
-        return encode(input, 0, input.length, flags);
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated
-     * byte[] with the result.
-     *
-     * @param input  the data to encode
-     * @param offset the position within the input array at which to
-     *               start
-     * @param len    the number of bytes of input to encode
-     * @param flags  controls certain features of the encoded output.
-     *               Passing {@code DEFAULT} results in output that
-     *               adheres to RFC 2045.
-     */
-    public static byte[] encode(byte[] input, int offset, int len, int flags) {
-        EncoderState state = new EncoderState(flags, null);
-
-        // Compute the exact length of the array we will produce.
-        int output_len = len / 3 * 4;
-
-        // Account for the tail of the data and the padding bytes, if any.
-        if (state.do_padding) {
-            if (len % 3 > 0) {
-                output_len += 4;
-            }
-        } else {
-            switch (len % 3) {
-                case 0: break;
-                case 1: output_len += 2; break;
-                case 2: output_len += 3; break;
-            }
-        }
-
-        // Account for the newlines, if any.
-        if (state.do_newline && len > 0) {
-            output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (state.do_cr ? 2 : 1);
-        }
-
-        state.output = new byte[output_len];
-        encodeInternal(input, offset, len, state, true);
-
-        assert state.op == output_len;
-
-        return state.output;
-    }
-
-    /* package */ static class EncoderState {
-        public byte[] output;
-        public int op;
-
-        final public byte[] tail;
-        public int tailLen;
-        public int count;
-
-        final public boolean do_padding;
-        final public boolean do_newline;
-        final public boolean do_cr;
-        final public byte[] alphabet;
-
-        public EncoderState(int flags, byte[] output) {
-            this.output = output;
-
-            do_padding = (flags & NO_PADDING) == 0;
-            do_newline = (flags & NO_WRAP) == 0;
-            do_cr = (flags & CRLF) != 0;
-            alphabet = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
-
-            tail = new byte[2];
-            tailLen = 0;
-
-            count = do_newline ? LINE_GROUPS : -1;
-        }
-    }
-
-    /**
-     * Encode another block of input data.
-     *
-     * @param estate an EncoderState object whose (caller-provided)
-     *        output array is big enough to hold all the encoded data.
-     *        On return, estate.op will be set to the length of the
-     *        encoded data.
-     * @param finish true if this is the final call to encodeInternal
-     *        with the given EncoderState object.  Will finalize the
-     *        encoder state and include any final bytes in the output.
-     */
-    static void encodeInternal(byte[] input, int offset, int len,
-                               final EncoderState estate, boolean finish) {
-        final boolean do_cr = estate.do_cr;
-        final boolean do_newline = estate.do_newline;
-        final boolean do_padding = estate.do_padding;
-        final byte[] output = estate.output;
-
-        int op = 0;
-
-        int p = offset;
-        len += offset;
-        int v = -1;
-        int count = estate.count;
-
-        // First we need to concatenate the tail of the previous call
-        // with any input bytes available now and see if we can empty
-        // the tail.
-
-        switch (estate.tailLen) {
-            case 0:
-                // There was no tail.
-                break;
-
-            case 1:
-                if (p+2 <= len) {
-                    // A 1-byte tail with at least 2 bytes of
-                    // input available now.
-                    v = ((estate.tail[0] & 0xff) << 16) |
-                        ((input[p++] & 0xff) << 8) |
-                        (input[p++] & 0xff);
-                    estate.tailLen = 0;
-                };
-                break;
-
-            case 2:
-                if (p+1 <= len) {
-                    // A 2-byte tail with at least 1 byte of input.
-                    v = ((estate.tail[0] & 0xff) << 16) |
-                        ((estate.tail[1] & 0xff) << 8) |
-                        (input[p++] & 0xff);
-                    estate.tailLen = 0;
-                }
-                break;
-        }
-
-        if (v != -1) {
-            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-            output[op++] = estate.alphabet[v & 0x3f];
-            if (--count == 0) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-                count = LINE_GROUPS;
-            }
-        }
-
-        // At this point either there is no tail, or there are fewer
-        // than 3 bytes of input available.
-
-        // The main loop, turning 3 input bytes into 4 output bytes on
-        // each iteration.
-        while (p+3 <= len) {
-            v = ((input[p++] & 0xff) << 16) |
-                ((input[p++] & 0xff) << 8) |
-                (input[p++] & 0xff);
-            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-            output[op++] = estate.alphabet[v & 0x3f];
-            if (--count == 0) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-                count = LINE_GROUPS;
-            }
-        }
-
-        if (finish) {
-            // Finish up the tail of the input.  Note that we need to
-            // consume any bytes in estate.tail before any bytes
-            // remaining in input; there should be at most two bytes
-            // total.
-
-            if (p-estate.tailLen == len-1) {
-                int t = 0;
-                v = ((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 4;
-                estate.tailLen -= t;
-                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-                output[op++] = estate.alphabet[v & 0x3f];
-                if (do_padding) {
-                    output[op++] = '=';
-                    output[op++] = '=';
-                }
-                if (do_newline) {
-                    if (do_cr) output[op++] = '\r';
-                    output[op++] = '\n';
-                }
-            } else if (p-estate.tailLen == len-2) {
-                int t = 0;
-                v = (((estate.tailLen > 1 ? estate.tail[t++] : input[p++]) & 0xff) << 10) |
-                    (((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 2);
-                estate.tailLen -= t;
-                output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-                output[op++] = estate.alphabet[v & 0x3f];
-                if (do_padding) {
-                    output[op++] = '=';
-                }
-                if (do_newline) {
-                    if (do_cr) output[op++] = '\r';
-                    output[op++] = '\n';
-                }
-            } else if (do_newline && op > 0 && count != LINE_GROUPS) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-            }
-
-            assert estate.tailLen == 0;
-            assert p == len;
-        } else {
-            // Save the leftovers in tail to be consumed on the next
-            // call to encodeInternal.
-
-            if (p == len-1) {
-                estate.tail[estate.tailLen++] = input[p];
-            } else if (p == len-2) {
-                estate.tail[estate.tailLen++] = input[p];
-                estate.tail[estate.tailLen++] = input[p+1];
-            }
-        }
-
-        estate.op = op;
-        estate.count = count;
-    }
-
-    private Base64() { }   // don't instantiate
-}
diff --git a/common/java/com/android/common/Base64InputStream.java b/common/java/com/android/common/Base64InputStream.java
deleted file mode 100644
index 1969bc4..0000000
--- a/common/java/com/android/common/Base64InputStream.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.common;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * An OutputStream that does either Base64 encoding or decoding on the
- * data written to it, writing the resulting data to another
- * OutputStream.
- */
-public class Base64InputStream extends FilterInputStream {
-    private final boolean encode;
-    private final Base64.EncoderState estate;
-    private final Base64.DecoderState dstate;
-
-    private static byte[] EMPTY = new byte[0];
-
-    private static final int BUFFER_SIZE = 2048;
-    private boolean eof;
-    private byte[] inputBuffer;
-    private byte[] outputBuffer;
-    private int outputStart;
-    private int outputEnd;
-
-    /**
-     * An InputStream that performs Base64 decoding on the data read
-     * from the wrapped stream.
-     *
-     * @param in the InputStream to read the source data from
-     * @param flags bit flags for controlling the decoder; see the
-     *        constants in {@link Base64}
-     */
-    public Base64InputStream(InputStream out, int flags) {
-        this(out, flags, false);
-    }
-
-    /**
-     * Performs Base64 encoding or decoding on the data read from the
-     * wrapped InputStream.
-     *
-     * @param in the InputStream to read the source data from
-     * @param flags bit flags for controlling the decoder; see the
-     *        constants in {@link Base64}
-     * @param encode true to encode, false to decode
-     */
-    public Base64InputStream(InputStream out, int flags, boolean encode) {
-        super(out);
-        this.encode = encode;
-        eof = false;
-        inputBuffer = new byte[BUFFER_SIZE];
-        if (encode) {
-            // len*8/5+10 is an overestimate of the most bytes the
-            // encoder can produce for len bytes of input.
-            outputBuffer = new byte[BUFFER_SIZE * 8/5 + 10];
-            estate = new Base64.EncoderState(flags, outputBuffer);
-            dstate = null;
-        } else {
-            // len*3/4+10 is an overestimate of the most bytes the
-            // decoder can produce for len bytes of input.
-            outputBuffer = new byte[BUFFER_SIZE * 3/4 + 10];
-            estate = null;
-            dstate = new Base64.DecoderState(flags, outputBuffer);
-        }
-        outputStart = 0;
-        outputEnd = 0;
-    }
-
-    public boolean markSupported() {
-        return false;
-    }
-
-    public void mark(int readlimit) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void reset() {
-        throw new UnsupportedOperationException();
-    }
-
-    public void close() throws IOException {
-        in.close();
-        inputBuffer = null;
-    }
-
-    public int available() {
-        return outputEnd - outputStart;
-    }
-
-    public long skip(long n) throws IOException {
-        if (outputStart >= outputEnd) {
-            refill();
-        }
-        if (outputStart >= outputEnd) {
-            return 0;
-        }
-        long bytes = Math.min(n, outputEnd-outputStart);
-        outputStart += bytes;
-        return bytes;
-    }
-
-    public int read() throws IOException {
-        if (outputStart >= outputEnd) {
-            refill();
-        }
-        if (outputStart >= outputEnd) {
-            return -1;
-        } else {
-            return outputBuffer[outputStart++];
-        }
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-        if (outputStart >= outputEnd) {
-            refill();
-        }
-        if (outputStart >= outputEnd) {
-            return -1;
-        }
-        int bytes = Math.min(len, outputEnd-outputStart);
-        System.arraycopy(outputBuffer, outputStart, b, off, bytes);
-        outputStart += bytes;
-        return bytes;
-    }
-
-    /**
-     * Read data from the input stream into inputBuffer, then
-     * decode/encode it into the empty outputBuffer, and reset the
-     * outputStart and outputEnd pointers.
-     */
-    private void refill() throws IOException {
-        if (eof) return;
-        int bytesRead = in.read(inputBuffer);
-        if (encode) {
-            if (bytesRead == -1) {
-                eof = true;
-                Base64.encodeInternal(EMPTY, 0, 0, estate, true);
-            } else {
-                Base64.encodeInternal(inputBuffer, 0, bytesRead, estate, false);
-            }
-            outputEnd = estate.op;
-        } else {
-            if (bytesRead == -1) {
-                eof = true;
-                Base64.decodeInternal(EMPTY, 0, 0, dstate, true);
-            } else {
-                Base64.decodeInternal(inputBuffer, 0, bytesRead, dstate, false);
-            }
-            outputEnd = dstate.op;
-        }
-        outputStart = 0;
-    }
-}
diff --git a/common/java/com/android/common/Base64OutputStream.java b/common/java/com/android/common/Base64OutputStream.java
deleted file mode 100644
index 76e1b6a..0000000
--- a/common/java/com/android/common/Base64OutputStream.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.common;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * An OutputStream that does either Base64 encoding or decoding on the
- * data written to it, writing the resulting data to another
- * OutputStream.
- */
-public class Base64OutputStream extends FilterOutputStream {
-    private final boolean encode;
-    private final Base64.EncoderState estate;
-    private final Base64.DecoderState dstate;
-    private final int flags;
-
-    private byte[] buffer = null;
-    private int bpos = 0;
-
-    private static byte[] EMPTY = new byte[0];
-
-    /**
-     * Performs Base64 encoding on the data written to the stream,
-     * writing the encoded data to another OutputStream.
-     *
-     * @param out the OutputStream to write the encoded data to
-     * @param flags bit flags for controlling the encoder; see the
-     *        constants in {@link Base64}
-     */
-    public Base64OutputStream(OutputStream out, int flags) {
-        this(out, flags, true);
-    }
-
-    /**
-     * Performs Base64 encoding or decoding on the data written to the
-     * stream, writing the encoded/decoded data to another
-     * OutputStream.
-     *
-     * @param out the OutputStream to write the encoded data to
-     * @param flags bit flags for controlling the encoder; see the
-     *        constants in {@link Base64}
-     * @param encode true to encode, false to decode
-     */
-    public Base64OutputStream(OutputStream out, int flags, boolean encode) {
-        super(out);
-        this.flags = flags;
-        this.encode = encode;
-        if (encode) {
-            estate = new Base64.EncoderState(flags, null);
-            dstate = null;
-        } else {
-            estate = null;
-            dstate = new Base64.DecoderState(flags, null);
-        }
-    }
-
-    public void write(int b) throws IOException {
-        // To avoid invoking the encoder/decoder routines for single
-        // bytes, we buffer up calls to write(int) in an internal
-        // byte array to transform them into writes of decently-sized
-        // arrays.
-
-        if (buffer == null) {
-            buffer = new byte[1024];
-        }
-        if (bpos >= buffer.length) {
-            // internal buffer full; write it out.
-            internalWrite(buffer, 0, bpos, false);
-            bpos = 0;
-        }
-        buffer[bpos++] = (byte) b;
-    }
-
-    /**
-     * Flush any buffered data from calls to write(int).  Needed
-     * before doing a write(byte[], int, int) or a close().
-     */
-    private void flushBuffer() throws IOException {
-        if (bpos > 0) {
-            internalWrite(buffer, 0, bpos, false);
-            bpos = 0;
-        }
-    }
-
-    public void write(byte[] b, int off, int len) throws IOException {
-        if (len <= 0) return;
-        flushBuffer();
-        internalWrite(b, off, len, false);
-    }
-
-    public void close() throws IOException {
-        flushBuffer();
-        internalWrite(EMPTY, 0, 0, true);
-        if ((flags & Base64.NO_CLOSE) == 0) {
-            out.close();
-        } else {
-            out.flush();
-        }
-    }
-
-    /**
-     * Write the given bytes to the encoder/decoder.
-     *
-     * @param finish true if this is the last batch of input, to cause
-     *        encoder/decoder state to be finalized.
-     */
-    private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
-        if (encode) {
-            // len*8/5+10 is an overestimate of the most bytes the
-            // encoder can produce for len bytes of input.
-            estate.output = embiggen(estate.output, len*8/5+10);
-            Base64.encodeInternal(b, off, len, estate, finish);
-            out.write(estate.output, 0, estate.op);
-        } else {
-            // len*3/4+10 is an overestimate of the most bytes the
-            // decoder can produce for len bytes of input.
-            dstate.output = embiggen(dstate.output, len*3/4+10);
-            if (!Base64.decodeInternal(b, off, len, dstate, finish)) {
-                throw new IOException("bad base-64");
-            }
-            out.write(dstate.output, 0, dstate.op);
-        }
-    }
-
-    /**
-     * If b.length is at least len, return b.  Otherwise return a new
-     * byte array of length len.
-     */
-    private byte[] embiggen(byte[] b, int len) {
-        if (b == null || b.length < len) {
-            return new byte[len];
-        } else {
-            return b;
-        }
-    }
-}
diff --git a/common/java/com/android/common/Patterns.java b/common/java/com/android/common/Patterns.java
index 71c3a5e..3b3b038 100644
--- a/common/java/com/android/common/Patterns.java
+++ b/common/java/com/android/common/Patterns.java
@@ -24,12 +24,12 @@
  */
 public class Patterns {
     /**
-     *  Regular expression pattern to match all IANA top-level domains.
+     *  Regular expression to match all IANA top-level domains.
      *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-     *  This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
+     *  This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+    public static final String TOP_LEVEL_DOMAIN_STR =
         "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
         + "|(biz|b[abdefghijmnorstvwyz])"
         + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
@@ -55,20 +55,22 @@
         + "|w[fs]"
         + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
         + "|y[etu]"
-        + "|z[amw])");
+        + "|z[amw])";
 
     /**
-     *  Regular expression pattern to match RFC 1738 URLs
+     *  Regular expression pattern to match all IANA top-level domains.
+     */
+    public static final Pattern TOP_LEVEL_DOMAIN =
+        Pattern.compile(TOP_LEVEL_DOMAIN_STR);
+
+    /**
+     *  Regular expression to match all IANA top-level domains for WEB_URL.
      *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-     *  This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
+     *  This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern WEB_URL = Pattern.compile(
-        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
-        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
-        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
-        + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
-        + "(?:"   // plus top level domain
+    public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
+        "(?:"
         + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
         + "|(?:biz|b[abdefghijmnorstvwyz])"
         + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
@@ -94,7 +96,28 @@
         + "|w[fs]"
         + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
         + "|y[etu]"
-        + "|z[amw]))"
+        + "|z[amw]))";
+
+    /**
+     * Good characters for Internationalized Resource Identifiers (IRI).
+     * This comprises most common used Unicode characters allowed in IRI
+     * as detailed in RFC 3987.
+     * Specifically, those two byte Unicode characters are not included.
+     */
+    public static final String GOOD_IRI_CHAR =
+        "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
+
+    /**
+     *  Regular expression pattern to match most part of RFC 3987
+     *  Internationalized URLs, aka IRIs.  Commonly used Unicode characters are
+     *  added.
+     */
+    public static final Pattern WEB_URL = Pattern.compile(
+        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+        + "((?:(?:[" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]{0,64}\\.)+"   // named host
+        + TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL
         + "|(?:(?:25[0-5]|2[0-4]" // or ip address
         + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
         + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
@@ -116,7 +139,7 @@
 
     public static final Pattern DOMAIN_NAME
         = Pattern.compile(
-            "(((([a-zA-Z0-9][a-zA-Z0-9\\-]*)*[a-zA-Z0-9]\\.)+"
+            "(((([" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]*)*[" + GOOD_IRI_CHAR + "]\\.)+"
             + TOP_LEVEL_DOMAIN + ")|"
             + IP_ADDRESS + ")");
 
diff --git a/common/java/com/android/common/ui/PointerLocationView.java b/common/java/com/android/common/ui/PointerLocationView.java
index e83c5ae..7bdb0bc 100644
--- a/common/java/com/android/common/ui/PointerLocationView.java
+++ b/common/java/com/android/common/ui/PointerLocationView.java
@@ -234,8 +234,9 @@
             }
             
             if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
-                final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
-                        >> MotionEvent.ACTION_POINTER_ID_SHIFT;
+                final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK)
+                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                final int id = event.getPointerId(index);
                 while (NP <= id) {
                     PointerState ps = new PointerState();
                     ps.mVelocity = VelocityTracker.obtain();
@@ -260,13 +261,14 @@
             }
             
             for (int i=0; i<NI; i++) {
-                final PointerState ps = mPointers.get(event.getPointerId(i));
+                final int id = event.getPointerId(i);
+                final PointerState ps = mPointers.get(id);
                 ps.mVelocity.addMovement(event);
                 ps.mVelocity.computeCurrentVelocity(1);
                 final int N = event.getHistorySize();
                 for (int j=0; j<N; j++) {
                     if (mPrintCoords) {
-                        Log.i("Pointer", "Pointer " + (i+1) + ": ("
+                        Log.i("Pointer", "Pointer " + (id+1) + ": ("
                                 + event.getHistoricalX(i, j)
                                 + ", " + event.getHistoricalY(i, j) + ")"
                                 + " Prs=" + event.getHistoricalPressure(i, j)
@@ -276,7 +278,7 @@
                     ps.mYs.add(event.getHistoricalY(i, j));
                 }
                 if (mPrintCoords) {
-                    Log.i("Pointer", "Pointer " + (i+1) + ": ("
+                    Log.i("Pointer", "Pointer " + (id+1) + ": ("
                             + event.getX(i) + ", " + event.getY(i) + ")"
                             + " Prs=" + event.getPressure(i)
                             + " Size=" + event.getSize(i));
@@ -293,8 +295,9 @@
             }
             
             if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
-                final int id = (action&MotionEvent.ACTION_POINTER_ID_MASK)
-                        >> MotionEvent.ACTION_POINTER_ID_SHIFT;
+                final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK)
+                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                final int id = event.getPointerId(index);
                 final PointerState ps = mPointers.get(id);
                 ps.mXs.add(Float.NaN);
                 ps.mYs.add(Float.NaN);
@@ -306,11 +309,12 @@
             
             if (action == MotionEvent.ACTION_UP) {
                 for (int i=0; i<NI; i++) {
-                    final PointerState ps = mPointers.get(event.getPointerId(i));
+                    final int id = event.getPointerId(i);
+                    final PointerState ps = mPointers.get(id);
                     if (ps.mCurDown) {
                         ps.mCurDown = false;
                         if (mPrintCoords) {
-                            Log.i("Pointer", "Pointer " + (i+1) + ": UP");
+                            Log.i("Pointer", "Pointer " + (id+1) + ": UP");
                         }
                     }
                 }
diff --git a/common/tests/src/com/android/common/Base64Test.java b/common/tests/src/com/android/common/Base64Test.java
deleted file mode 100644
index 1064625f2..0000000
--- a/common/tests/src/com/android/common/Base64Test.java
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.common;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.Random;
-
-public class Base64Test extends TestCase {
-    private static final String TAG = "B64Test";
-
-    /** Decodes a string, returning a string. */
-    private String decodeString(String in) throws Exception {
-        byte[] out = Base64.decode(in, 0);
-        return new String(out);
-    }
-
-    /**
-     * Encodes the string 'in' using 'flags'.  Asserts that decoding
-     * gives the same string.  Returns the encoded string.
-     */
-    private String encodeToString(String in, int flags) throws Exception {
-        String b64 = Base64.encodeToString(in.getBytes(), flags);
-        String dec = decodeString(b64);
-        assertEquals(in, dec);
-        return b64;
-    }
-
-    /** Assert that decoding 'in' throws IllegalArgumentException. */
-    private void assertBad(String in) throws Exception {
-        try {
-            byte[] out = Base64.decode(in, 0);
-            fail("should have failed to decode");
-        } catch (IllegalArgumentException e) {
-        }
-    }
-
-    /** Assert that actual equals the first len bytes of expected. */
-    private void assertEquals(byte[] expected, int len, byte[] actual) {
-        assertEquals(len, actual.length);
-        for (int i = 0; i < len; ++i) {
-            assertEquals(expected[i], actual[i]);
-        }
-    }
-
-    /** Assert that actual equals the first len bytes of expected. */
-    private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
-        assertEquals(len, alen);
-        for (int i = 0; i < len; ++i) {
-            assertEquals(expected[i], actual[i]);
-        }
-    }
-
-    /** Assert that actual equals the first len bytes of expected. */
-    private void assertEquals(byte[] expected, byte[] actual) {
-        assertEquals(expected.length, actual.length);
-        for (int i = 0; i < expected.length; ++i) {
-            assertEquals(expected[i], actual[i]);
-        }
-    }
-
-    public void testDecodeExtraChars() throws Exception {
-        // padding 0
-        assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
-        assertBad("aGVsbG8sIHdvcmxk=");
-        assertBad("aGVsbG8sIHdvcmxk==");
-        assertBad("aGVsbG8sIHdvcmxk =");
-        assertBad("aGVsbG8sIHdvcmxk = = ");
-        assertEquals("hello, world", decodeString(" aGVs bG8s IHdv cmxk  "));
-        assertEquals("hello, world", decodeString(" aGV sbG8 sIHd vcmx k "));
-        assertEquals("hello, world", decodeString(" aG VsbG 8sIH dvcm xk "));
-        assertEquals("hello, world", decodeString(" a GVsb G8sI Hdvc mxk "));
-        assertEquals("hello, world", decodeString(" a G V s b G 8 s I H d v c m x k "));
-        assertEquals("hello, world", decodeString("_a*G_V*s_b*G_8*s_I*H_d*v_c*m_x*k_"));
-        assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
-
-        // padding 1
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE="));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE"));
-        assertBad("aGVsbG8sIHdvcmxkPyE==");
-        assertBad("aGVsbG8sIHdvcmxkPyE ==");
-        assertBad("aGVsbG8sIHdvcmxkPyE = = ");
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E="));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E"));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ="));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E "));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E = "));
-        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E   "));
-
-        // padding 2
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg=="));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg"));
-        assertBad("aGVsbG8sIHdvcmxkLg=");
-        assertBad("aGVsbG8sIHdvcmxkLg =");
-        assertBad("aGVsbG8sIHdvcmxkLg = ");
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g=="));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g"));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g =="));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g "));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g = = "));
-        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g   "));
-    }
-
-    private static final byte[] BYTES = { (byte) 0xff, (byte) 0xee, (byte) 0xdd,
-                                          (byte) 0xcc, (byte) 0xbb, (byte) 0xaa,
-                                          (byte) 0x99, (byte) 0x88, (byte) 0x77 };
-
-    public void testBinaryDecode() throws Exception {
-        assertEquals(BYTES, 0, Base64.decode("", 0));
-        assertEquals(BYTES, 1, Base64.decode("/w==", 0));
-        assertEquals(BYTES, 2, Base64.decode("/+4=", 0));
-        assertEquals(BYTES, 3, Base64.decode("/+7d", 0));
-        assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
-        assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
-        assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
-        assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
-        assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
-    }
-
-    public void testWebSafe() throws Exception {
-        assertEquals(BYTES, 0, Base64.decode("", Base64.WEB_SAFE));
-        assertEquals(BYTES, 1, Base64.decode("_w==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.WEB_SAFE));
-        assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.WEB_SAFE));
-        assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.WEB_SAFE));
-        assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.WEB_SAFE));
-        assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.WEB_SAFE));
-
-        assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.WEB_SAFE));
-        assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.WEB_SAFE));
-        assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.WEB_SAFE));
-        assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.WEB_SAFE));
-        assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.WEB_SAFE));
-        assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.WEB_SAFE));
-    }
-
-    public void testFlags() throws Exception {
-        assertEquals("YQ==\n",       encodeToString("a", 0));
-        assertEquals("YQ==",         encodeToString("a", Base64.NO_WRAP));
-        assertEquals("YQ\n",         encodeToString("a", Base64.NO_PADDING));
-        assertEquals("YQ",           encodeToString("a", Base64.NO_PADDING | Base64.NO_WRAP));
-        assertEquals("YQ==\r\n",     encodeToString("a", Base64.CRLF));
-        assertEquals("YQ\r\n",       encodeToString("a", Base64.CRLF | Base64.NO_PADDING));
-
-        assertEquals("YWI=\n",       encodeToString("ab", 0));
-        assertEquals("YWI=",         encodeToString("ab", Base64.NO_WRAP));
-        assertEquals("YWI\n",        encodeToString("ab", Base64.NO_PADDING));
-        assertEquals("YWI",          encodeToString("ab", Base64.NO_PADDING | Base64.NO_WRAP));
-        assertEquals("YWI=\r\n",     encodeToString("ab", Base64.CRLF));
-        assertEquals("YWI\r\n",      encodeToString("ab", Base64.CRLF | Base64.NO_PADDING));
-
-        assertEquals("YWJj\n",       encodeToString("abc", 0));
-        assertEquals("YWJj",         encodeToString("abc", Base64.NO_WRAP));
-        assertEquals("YWJj\n",       encodeToString("abc", Base64.NO_PADDING));
-        assertEquals("YWJj",         encodeToString("abc", Base64.NO_PADDING | Base64.NO_WRAP));
-        assertEquals("YWJj\r\n",     encodeToString("abc", Base64.CRLF));
-        assertEquals("YWJj\r\n",     encodeToString("abc", Base64.CRLF | Base64.NO_PADDING));
-
-        assertEquals("YWJjZA==\n",   encodeToString("abcd", 0));
-        assertEquals("YWJjZA==",     encodeToString("abcd", Base64.NO_WRAP));
-        assertEquals("YWJjZA\n",     encodeToString("abcd", Base64.NO_PADDING));
-        assertEquals("YWJjZA",       encodeToString("abcd", Base64.NO_PADDING | Base64.NO_WRAP));
-        assertEquals("YWJjZA==\r\n", encodeToString("abcd", Base64.CRLF));
-        assertEquals("YWJjZA\r\n",   encodeToString("abcd", Base64.CRLF | Base64.NO_PADDING));
-    }
-
-    public void testLineLength() throws Exception {
-        String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd";
-        String in_57 = in_56 + "e";
-        String in_58 = in_56 + "ef";
-        String in_59 = in_56 + "efg";
-        String in_60 = in_56 + "efgh";
-        String in_61 = in_56 + "efghi";
-
-        String prefix = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5emFi";
-        String out_56 = prefix + "Y2Q=\n";
-        String out_57 = prefix + "Y2Rl\n";
-        String out_58 = prefix + "Y2Rl\nZg==\n";
-        String out_59 = prefix + "Y2Rl\nZmc=\n";
-        String out_60 = prefix + "Y2Rl\nZmdo\n";
-        String out_61 = prefix + "Y2Rl\nZmdoaQ==\n";
-
-        // no newline for an empty input array.
-        assertEquals("", encodeToString("", 0));
-
-        assertEquals(out_56, encodeToString(in_56, 0));
-        assertEquals(out_57, encodeToString(in_57, 0));
-        assertEquals(out_58, encodeToString(in_58, 0));
-        assertEquals(out_59, encodeToString(in_59, 0));
-        assertEquals(out_60, encodeToString(in_60, 0));
-        assertEquals(out_61, encodeToString(in_61, 0));
-
-        assertEquals(out_56.replaceAll("=", ""), encodeToString(in_56, Base64.NO_PADDING));
-        assertEquals(out_57.replaceAll("=", ""), encodeToString(in_57, Base64.NO_PADDING));
-        assertEquals(out_58.replaceAll("=", ""), encodeToString(in_58, Base64.NO_PADDING));
-        assertEquals(out_59.replaceAll("=", ""), encodeToString(in_59, Base64.NO_PADDING));
-        assertEquals(out_60.replaceAll("=", ""), encodeToString(in_60, Base64.NO_PADDING));
-        assertEquals(out_61.replaceAll("=", ""), encodeToString(in_61, Base64.NO_PADDING));
-
-        assertEquals(out_56.replaceAll("\n", ""), encodeToString(in_56, Base64.NO_WRAP));
-        assertEquals(out_57.replaceAll("\n", ""), encodeToString(in_57, Base64.NO_WRAP));
-        assertEquals(out_58.replaceAll("\n", ""), encodeToString(in_58, Base64.NO_WRAP));
-        assertEquals(out_59.replaceAll("\n", ""), encodeToString(in_59, Base64.NO_WRAP));
-        assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP));
-        assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP));
-    }
-
-    /**
-     * Tests that Base64.encodeInternal does correct handling of the
-     * tail for each call.
-     *
-     * This test is disabled because while it passes if you can get it
-     * to run, android's test infrastructure currently doesn't allow
-     * us to get at package-private members (Base64.EncoderState in
-     * this case).
-     */
-    public void XXXtestEncodeInternal() throws Exception {
-        byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
-        byte[] output = new byte[100];
-
-        Base64.EncoderState state = new Base64.EncoderState(Base64.NO_PADDING | Base64.NO_WRAP,
-                                                            output);
-
-        Base64.encodeInternal(input, 0, 3, state, false);
-        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 3, state, false);
-        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals(0, state.op);
-        assertEquals(1, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals(0, state.op);
-        assertEquals(2, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals("YWFh".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals(0, state.op);
-        assertEquals(2, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals("YWJh".getBytes(), 4, state.output, state.op);
-        assertEquals(1, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals("YmFi".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
-
-        Base64.encodeInternal(input, 0, 1, state, true);
-        assertEquals("YQ".getBytes(), 2, state.output, state.op);
-    }
-
-    private static final String lipsum =
-            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
-            "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " +
-            "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " +
-            "urna, pharetra vitae consequat eget, adipiscing eu ante. " +
-            "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " +
-            "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " +
-            "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " +
-            "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " +
-            "aliquet dui sapien a turpis. Donec ultricies varius ligula, " +
-            "ut hendrerit arcu malesuada at. Praesent sed elit pretium " +
-            "eros luctus gravida. In ac dolor lorem. Cras condimentum " +
-            "convallis elementum. Phasellus vel felis in nulla ultrices " +
-            "venenatis. Nam non tortor non orci convallis convallis. " +
-            "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " +
-            "tristique senectus et netus et malesuada fames ac turpis " +
-            "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " +
-            "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " +
-            "Phasellus posuere, leo at ultricies vehicula, massa risus " +
-            "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " +
-            "molestie dapibus commodo. Ut vel tellus at massa gravida " +
-            "semper non sed orci.";
-
-    public void testInputStream() throws Exception {
-        int[] flagses = { Base64.DEFAULT,
-                          Base64.NO_PADDING,
-                          Base64.NO_WRAP,
-                          Base64.NO_PADDING | Base64.NO_WRAP,
-                          Base64.CRLF,
-                          Base64.WEB_SAFE };
-        int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
-        Random rng = new Random(32176L);
-
-        // Test input needs to be at least 2048 bytes to fill up the
-        // read buffer of Base64InputStream.
-        byte[] plain = (lipsum + lipsum + lipsum + lipsum + lipsum).getBytes();
-
-        for (int flags: flagses) {
-            byte[] encoded = Base64.encode(plain, flags);
-
-            ByteArrayInputStream bais;
-            Base64InputStream b64is;
-            byte[] actual = new byte[plain.length * 2];
-            int ap;
-            int b;
-
-            // ----- test decoding ("encoded" -> "plain") -----
-
-            // read as much as it will give us in one chunk
-            bais = new ByteArrayInputStream(encoded);
-            b64is = new Base64InputStream(bais, flags);
-            ap = 0;
-            while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
-                ap += b;
-            }
-            assertEquals(actual, ap, plain);
-
-            // read individual bytes
-            bais = new ByteArrayInputStream(encoded);
-            b64is = new Base64InputStream(bais, flags);
-            ap = 0;
-            while ((b = b64is.read()) != -1) {
-                actual[ap++] = (byte) b;
-            }
-            assertEquals(actual, ap, plain);
-
-            // mix reads of variously-sized arrays with one-byte reads
-            bais = new ByteArrayInputStream(encoded);
-            b64is = new Base64InputStream(bais, flags);
-            ap = 0;
-            readloop: while (true) {
-                int l = writeLengths[rng.nextInt(writeLengths.length)];
-                if (l >= 0) {
-                    b = b64is.read(actual, ap, l);
-                    if (b == -1) break readloop;
-                    ap += b;
-                } else {
-                    for (int i = 0; i < -l; ++i) {
-                        if ((b = b64is.read()) == -1) break readloop;
-                        actual[ap++] = (byte) b;
-                    }
-                }
-            }
-            assertEquals(actual, ap, plain);
-
-            // ----- test encoding ("plain" -> "encoded") -----
-
-            // read as much as it will give us in one chunk
-            bais = new ByteArrayInputStream(plain);
-            b64is = new Base64InputStream(bais, flags, true);
-            ap = 0;
-            while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
-                ap += b;
-            }
-            assertEquals(actual, ap, encoded);
-
-            // read individual bytes
-            bais = new ByteArrayInputStream(plain);
-            b64is = new Base64InputStream(bais, flags, true);
-            ap = 0;
-            while ((b = b64is.read()) != -1) {
-                actual[ap++] = (byte) b;
-            }
-            assertEquals(actual, ap, encoded);
-
-            // mix reads of variously-sized arrays with one-byte reads
-            bais = new ByteArrayInputStream(plain);
-            b64is = new Base64InputStream(bais, flags, true);
-            ap = 0;
-            readloop: while (true) {
-                int l = writeLengths[rng.nextInt(writeLengths.length)];
-                if (l >= 0) {
-                    b = b64is.read(actual, ap, l);
-                    if (b == -1) break readloop;
-                    ap += b;
-                } else {
-                    for (int i = 0; i < -l; ++i) {
-                        if ((b = b64is.read()) == -1) break readloop;
-                        actual[ap++] = (byte) b;
-                    }
-                }
-            }
-            assertEquals(actual, ap, encoded);
-        }
-    }
-
-    /**
-     * Tests that Base64OutputStream produces exactly the same results
-     * as calling Base64.encode/.decode on an in-memory array.
-     */
-    public void testOutputStream() throws Exception {
-        int[] flagses = { Base64.DEFAULT,
-                          Base64.NO_PADDING,
-                          Base64.NO_WRAP,
-                          Base64.NO_PADDING | Base64.NO_WRAP,
-                          Base64.CRLF,
-                          Base64.WEB_SAFE };
-        int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
-        Random rng = new Random(32176L);
-
-        // Test input needs to be at least 1024 bytes to test filling
-        // up the write(int) buffer of Base64OutputStream.
-        byte[] plain = (lipsum + lipsum).getBytes();
-
-        for (int flags: flagses) {
-            byte[] encoded = Base64.encode(plain, flags);
-
-            ByteArrayOutputStream baos;
-            Base64OutputStream b64os;
-            byte[] actual;
-            int p;
-
-            // ----- test encoding ("plain" -> "encoded") -----
-
-            // one large write(byte[]) of the whole input
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags);
-            b64os.write(plain);
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(encoded, actual);
-
-            // many calls to write(int)
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags);
-            for (int i = 0; i < plain.length; ++i) {
-                b64os.write(plain[i]);
-            }
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(encoded, actual);
-
-            // intermixed sequences of write(int) with
-            // write(byte[],int,int) of various lengths.
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags);
-            p = 0;
-            while (p < plain.length) {
-                int l = writeLengths[rng.nextInt(writeLengths.length)];
-                l = Math.min(l, plain.length-p);
-                if (l >= 0) {
-                    b64os.write(plain, p, l);
-                    p += l;
-                } else {
-                    l = Math.min(-l, plain.length-p);
-                    for (int i = 0; i < l; ++i) {
-                        b64os.write(plain[p+i]);
-                    }
-                    p += l;
-                }
-            }
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(encoded, actual);
-
-            // ----- test decoding ("encoded" -> "plain") -----
-
-            // one large write(byte[]) of the whole input
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags, false);
-            b64os.write(encoded);
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(plain, actual);
-
-            // many calls to write(int)
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags, false);
-            for (int i = 0; i < encoded.length; ++i) {
-                b64os.write(encoded[i]);
-            }
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(plain, actual);
-
-            // intermixed sequences of write(int) with
-            // write(byte[],int,int) of various lengths.
-            baos = new ByteArrayOutputStream();
-            b64os = new Base64OutputStream(baos, flags, false);
-            p = 0;
-            while (p < encoded.length) {
-                int l = writeLengths[rng.nextInt(writeLengths.length)];
-                l = Math.min(l, encoded.length-p);
-                if (l >= 0) {
-                    b64os.write(encoded, p, l);
-                    p += l;
-                } else {
-                    l = Math.min(-l, encoded.length-p);
-                    for (int i = 0; i < l; ++i) {
-                        b64os.write(encoded[p+i]);
-                    }
-                    p += l;
-                }
-            }
-            b64os.close();
-            actual = baos.toByteArray();
-            assertEquals(plain, actual);
-        }
-    }
-}
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/common/tests/src/com/android/common/PatternsTest.java
index 635601e..9e2ad58 100644
--- a/common/tests/src/com/android/common/PatternsTest.java
+++ b/common/tests/src/com/android/common/PatternsTest.java
@@ -68,6 +68,12 @@
         t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
         assertTrue("Valid URL", t);
 
+        // Internationalized URL.
+        t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
+        assertTrue("Valid URL", t);
+        t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
+        assertTrue("Valid URL", t);
+
         t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
         assertFalse("Matched invalid protocol", t);
 
@@ -99,6 +105,13 @@
         t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
         assertTrue("Valid domain", t);
 
+        t = Patterns.WEB_URL.matcher("google.me").matches();
+        assertTrue("Valid domain", t);
+
+        // Internationalized domains.
+        t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
+        assertTrue("Valid domain", t);
+
         t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
         assertFalse("Invalid domain", t);
     }
diff --git a/common/tools/make-iana-tld-pattern.py b/common/tools/make-iana-tld-pattern.py
index ece4dcf..de81c58 100755
--- a/common/tools/make-iana-tld-pattern.py
+++ b/common/tools/make-iana-tld-pattern.py
@@ -4,43 +4,27 @@
 
 TLD_PREFIX = r"""
     /**
-     *  Regular expression pattern to match all IANA top-level domains.
+     *  Regular expression to match all IANA top-level domains.
      *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
      *  This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+    public static final String TOP_LEVEL_DOMAIN_STR =
 """
-TLD_SUFFIX = '");'
+TLD_SUFFIX = '";'
 
 URL_PREFIX = r"""
     /**
-     *  Regular expression pattern to match RFC 1738 URLs
+     *  Regular expression to match all IANA top-level domains for WEB_URL.
      *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-     *  This pattern is auto-generated by frameworkds/base/common/tools/make-iana-tld-pattern.py
+     *  This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern WEB_URL = Pattern.compile(
-        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
-        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
-        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
-        + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
-        + "(?:"   // plus top level domain
+    public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
+        "(?:"
 """
 
-URL_SUFFIX = r"""
-        + "|(?:(?:25[0-5]|2[0-4]" // or ip address
-        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
-        + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
-        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
-        + "|[1-9][0-9]|[0-9])))"
-        + "(?:\\:\\d{1,5})?)" // plus option port number
-        + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
-        + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
-        + "(?:\\b|$)"); // and finally, a word boundary or end of
-                        // input.  This is to stop foo.sure from
-                        // matching as foo.su
-"""
+URL_SUFFIX = ';'
 
 class Bucket:
     def __init__(self, baseLetter):
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b4fe698..db6a4bf 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2659,102 +2659,6 @@
             return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         }
 
-        // Constants related to app heuristics
-        // No-installation limit for internal flash: 10% or less space available
-        private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;
-
-        // SD-to-internal app size threshold: currently set to 1 MB
-        private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
-
-        public int recommendAppInstallLocation(Package pkg) {
-            // Initial implementation:
-            // Package size = code size + cache size + data size
-            // If code size > 1 MB, install on SD card.
-            // Else install on internal NAND flash, unless space on NAND is less than 10%
-
-            if (pkg == null) {
-                return INSTALL_PARSE_FAILED_NOT_APK;
-            }
-
-            StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath());
-            StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
-
-            long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() *
-                    (long)internalFlashStats.getBlockSize();
-            long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() *
-                    (long)internalFlashStats.getBlockSize();
-            long availSDSize = (long)sdcardStats.getAvailableBlocks() *
-                    (long)sdcardStats.getBlockSize();
-
-            double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;
-
-            final String archiveFilePath = pkg.mScanPath;
-            File apkFile = new File(archiveFilePath);
-            long pkgLen = apkFile.length();
-
-            boolean auto = true;
-            // To make final copy
-            long reqInstallSize = pkgLen;
-            // For dex files
-            long reqInternalSize = 1 * pkgLen;
-            boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
-            boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
-            boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
-                    (reqInternalSize < availInternalFlashSize);
-            boolean fitsOnInt = intThresholdOk && intAvailOk;
-
-            // Consider application flags preferences as well...
-            boolean installOnlyOnSd = (pkg.installLocation ==
-                    PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
-            boolean installOnlyInternal = (pkg.installLocation ==
-                    PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-            if (installOnlyInternal) {
-                // If set explicitly in manifest,
-                // let that override everything else
-                auto = false;
-            } else if (installOnlyOnSd){
-                // Check if this can be accommodated on the sdcard
-                if (fitsOnSd) {
-                    auto = false;
-                }
-            } else {
-                // Check if user option is enabled
-                boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(),
-                        Settings.System.SET_INSTALL_LOCATION, 0) != 0;
-                if (setInstallLoc) {
-                    // Pick user preference
-                    int installPreference = Settings.System.getInt(mContext.getContentResolver(),
-                            Settings.System.DEFAULT_INSTALL_LOCATION,
-                            PackageInfo.INSTALL_LOCATION_AUTO);
-                    if (installPreference == 1) {
-                        installOnlyInternal = true;
-                        auto = false;
-                    } else if (installPreference == 2) {
-                        installOnlyOnSd = true;
-                        auto = false;
-                    }
-                }
-            }
-            if (!auto) {
-                if (installOnlyOnSd) {
-                    return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                } else if (installOnlyInternal){
-                    // Check on internal flash
-                    return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                }
-            }
-            // Try to install internally
-            if (fitsOnInt) {
-                return INSTALL_ON_INTERNAL_FLASH;
-            }
-            // Try the sdcard now.
-            if (fitsOnSd) {
-                return INSTALL_ON_SDCARD;
-            }
-            // Return error code
-            return INSTALL_FAILED_INSUFFICIENT_STORAGE;
-        }
-
         private final ContextImpl mContext;
         private final IPackageManager mPM;
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e36eba9..d31b25b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1840,7 +1840,7 @@
      * @hide
      */
     public static final String ACTION_REMOTE_INTENT =
-            "android.intent.action.REMOTE_INTENT";
+            "com.google.android.pushmessaging.intent.RECEIVE";
 
     /**
      * Broadcast Action: hook for permforming cleanup after a system update.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 17bee48..ff2ed3d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -258,14 +258,7 @@
      * package has to be installed on the sdcard.
      * @hide
      */
-    public static final int INSTALL_ON_SDCARD = 0x00000008;
-
-    /**
-     * Convenience flag parameter to indicate that this package has to be installed
-     * on internal flash.
-     * @hide
-     */
-    public static final int INSTALL_ON_INTERNAL_FLASH = 0x00000000;
+    public static final int INSTALL_EXTERNAL = 0x00000008;
 
     /**
      * Flag parameter for
@@ -529,6 +522,14 @@
     public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
 
     /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because of system issues.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
+
+    /**
      * Indicates the state of installation. Used by PackageManager to
      * figure out incomplete installations. Say a package is being installed
      * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till
@@ -627,23 +628,6 @@
      */
     public static final String ACTION_CLEAN_EXTERNAL_STORAGE
             = "android.content.pm.CLEAN_EXTERNAL_STORAGE";
-    
-    /**
-     * Determines best place to install an application: either SD or internal FLASH.
-     * If applications explicitly set installLocation in their manifest, that
-     * preference takes precedence. If not a recommended location is returned
-     * based on current available storage on internal flash or sdcard.
-     * @param pkgInfo PackageParser.Package of the package that is to be installed.
-     * Call utility method to obtain.
-     * @return {@link INSTALL_ON_INTERNAL_FLASH} if it is best to install package on internal
-     * storage, {@link INSTALL_ON_SDCARD} if it is best to install package on SD card,
-     * and {@link INSTALL_FAILED_INSUFFICIENT_STORAGE} if insufficient space to safely install
-     * the application. {@link INSTALL_PARSE_FAILED_NOT_APK} Is returned if any input
-     * parameter is <code>null</code>.
-     * This recommendation does take into account the package's own flags.
-     * @hide
-     */
-    public abstract int recommendAppInstallLocation(PackageParser.Package pkg);
 
     /**
      * Retrieve overall information about an application package that is
diff --git a/core/java/android/net/Downloads.java b/core/java/android/net/Downloads.java
index b86a0e2..72106c8 100644
--- a/core/java/android/net/Downloads.java
+++ b/core/java/android/net/Downloads.java
@@ -22,165 +22,197 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.provider.BaseColumns;
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
 
 /**
  * The Download Manager
  *
- * @pending
+ *
  */
 public final class Downloads {
 
-    public static final class ByUri {
 
+    /**
+     * Download status codes
+     */
+
+    /**
+     * This download hasn't started yet
+     */
+    public static final int STATUS_PENDING = 190;
+
+    /**
+     * This download has started
+     */
+    public static final int STATUS_RUNNING = 192;
+
+    /**
+     * This download has successfully completed.
+     * Warning: there might be other status values that indicate success
+     * in the future.
+     * Use isSucccess() to capture the entire category.
+     */
+    public static final int STATUS_SUCCESS = 200;
+
+    /**
+     * This download can't be performed because the content type cannot be
+     * handled.
+     */
+    public static final int STATUS_NOT_ACCEPTABLE = 406;
+
+    /**
+     * This download has completed with an error.
+     * Warning: there will be other status values that indicate errors in
+     * the future. Use isStatusError() to capture the entire category.
+     */
+    public static final int STATUS_UNKNOWN_ERROR = 491;
+
+    /**
+     * This download couldn't be completed because of an HTTP
+     * redirect response that the download manager couldn't
+     * handle.
+     */
+    public static final int STATUS_UNHANDLED_REDIRECT = 493;
+
+    /**
+     * This download couldn't be completed due to insufficient storage
+     * space.  Typically, this is because the SD card is full.
+     */
+    public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
+
+    /**
+     * This download couldn't be completed because no external storage
+     * device was found.  Typically, this is because the SD card is not
+     * mounted.
+     */
+    public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
+
+    /**
+     * Returns whether the status is a success (i.e. 2xx).
+     */
+    public static boolean isStatusSuccess(int status) {
+        return (status >= 200 && status < 300);
+    }
+
+    /**
+     * Returns whether the status is an error (i.e. 4xx or 5xx).
+     */
+    public static boolean isStatusError(int status) {
+        return (status >= 400 && status < 600);
+    }
+
+    /**
+     * Download destinations
+     */
+
+    /**
+     * This download will be saved to the external storage. This is the
+     * default behavior, and should be used for any file that the user
+     * can freely access, copy, delete. Even with that destination,
+     * unencrypted DRM files are saved in secure internal storage.
+     * Downloads to the external destination only write files for which
+     * there is a registered handler. The resulting files are accessible
+     * by filename to all applications.
+     */
+    public static final int DOWNLOAD_DESTINATION_EXTERNAL = 1;
+
+    /**
+     * This download will be saved to the download manager's private
+     * partition. This is the behavior used by applications that want to
+     * download private files that are used and deleted soon after they
+     * get downloaded. All file types are allowed, and only the initiating
+     * application can access the file (indirectly through a content
+     * provider). This requires the
+     * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.
+     */
+    public static final int DOWNLOAD_DESTINATION_CACHE = 2;
+
+    /**
+     * This download will be saved to the download manager's private
+     * partition and will be purged as necessary to make space. This is
+     * for private files (similar to CACHE_PARTITION) that aren't deleted
+     * immediately after they are used, and are kept around by the download
+     * manager as long as space is available.
+     */
+    public static final int DOWNLOAD_DESTINATION_CACHE_PURGEABLE = 3;
+
+
+    /**
+     * An invalid download id
+     */
+    public static final long DOWNLOAD_ID_INVALID = -1;
+
+
+    /**
+     * Broadcast Action: this is sent by the download manager to the app
+     * that had initiated a download when that download completes. The
+     * download's content: uri is specified in the intent's data.
+     */
+    public static final String ACTION_DOWNLOAD_COMPLETED =
+            "android.intent.action.DOWNLOAD_COMPLETED";
+
+    /**
+     * If extras are specified when requesting a download they will be provided in the intent that
+     * is sent to the specified class and package when a download has finished.
+     * <P>Type: TEXT</P>
+     * <P>Owner can Init</P>
+     */
+    public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
+
+
+    /**
+     * Status class for a download
+     */
+    public static final class StatusInfo {
+        public boolean completed = false;
+        /** The filename of the active download. */
+        public String filename = null;
+        /** An opaque id for the download */
+        public long id = DOWNLOAD_ID_INVALID;
+        /** An opaque status code for the download */
+        public int statusCode = -1;
+        /** Approximate number of bytes downloaded so far, for debugging purposes. */
+        public long bytesSoFar = -1;
+
+        /**
+         * Returns whether the download is completed
+         * @return a boolean whether the download is complete.
+         */
+        public boolean isComplete() {
+            return android.provider.Downloads.Impl.isStatusCompleted(statusCode);
+        }
+
+        /**
+         * Returns whether the download is successful
+         * @return a boolean whether the download is successful.
+         */
+        public boolean isSuccessful() {
+            return android.provider.Downloads.Impl.isStatusCompleted(statusCode);
+        }
+    }
+
+    /**
+     * Class to access initiate and query download by server uri
+     */
+    public static final class ByUri extends DownloadBase {
         /** @hide */
         private ByUri() {}
 
         /**
-          * Initiate a download where the download will be tracked by its URI.
-          * @pending
-          */
-        public static boolean startDownloadByUri(
-                Context context,
-                String url,
-                boolean showDownload,
-                boolean allowRoaming,
-                String title,
-                String notification_package,
-                String notification_class) {
-            ContentResolver cr = context.getContentResolver();
-
-            // Tell download manager to start downloading update.
-            ContentValues values = new ContentValues();
-            values.put(android.provider.Downloads.Impl.COLUMN_URI, url);
-            values.put(android.provider.Downloads.Impl.COLUMN_VISIBILITY,
-                       showDownload ? android.provider.Downloads.Impl.VISIBILITY_VISIBLE
-                       : android.provider.Downloads.Impl.VISIBILITY_HIDDEN);
-            if (title != null) {
-                values.put(android.provider.Downloads.Impl.COLUMN_TITLE, title);
-            }
-            values.put(android.provider.Downloads.Impl.COLUMN_APP_DATA, url);
-            values.put(android.provider.Downloads.Impl.COLUMN_DESTINATION,
-                       allowRoaming ? android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION :
-                       android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING);
-            values.put(android.provider.Downloads.Impl.COLUMN_NO_INTEGRITY, true);  // Don't check ETag
-            if (notification_package != null && notification_class != null) {
-                values.put(android.provider.Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, notification_package);
-                values.put(android.provider.Downloads.Impl.COLUMN_NOTIFICATION_CLASS, notification_class);
-            }
-
-            if (cr.insert(android.provider.Downloads.Impl.CONTENT_URI, values) == null) {
-                return false;
-            }
-            return true;
-        }
-
-        public static final class StatusInfo {
-            public boolean completed = false;
-            /** The filename of the active download. */
-            public String filename = null;
-            /** An opaque id for the download */
-            public long id = -1;
-            /** An opaque status code for the download */
-            public int statusCode = -1;
-            /** Approximate number of bytes downloaded so far, for debugging purposes. */
-            public long bytesSoFar = -1;
-        }
-
-        /** @hide */
-        private static final int STATUS_INVALID = 0;
-        /** @hide */
-        private static final int STATUS_DOWNLOADING_UPDATE = 3;
-        /** @hide */
-        private static final int STATUS_DOWNLOADED_UPDATE = 4;
-
-        /**
-         * Column projection for the query to the download manager. This must match
-         * with the constants DOWNLOADS_COLUMN_*.
-          * @hide
-         */
-        private static final String[] DOWNLOADS_PROJECTION = {
-            BaseColumns._ID,
-            android.provider.Downloads.Impl.COLUMN_APP_DATA,
-            android.provider.Downloads.Impl.COLUMN_STATUS,
-            android.provider.Downloads.Impl._DATA,
-            android.provider.Downloads.Impl.COLUMN_LAST_MODIFICATION,
-            android.provider.Downloads.Impl.COLUMN_CURRENT_BYTES,
-        };
-
-        /**
-          * The column index for the ID.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_ID = 0;
-        /**
-          * The column index for the URI.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_URI = 1;
-        /**
-          * The column index for the status code.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_STATUS = 2;
-        /**
-          * The column index for the filename.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_FILENAME = 3;
-        /**
-          * The column index for the last modification time.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_LAST_MODIFICATION = 4;
-        /**
-          * The column index for the number of bytes downloaded so far.
-          * @hide
-          */
-        private static final int DOWNLOADS_COLUMN_CURRENT_BYTES = 5;
-
-        /**
-         * Gets the status of a download.
-         *
-         * @param c A Cursor pointing to a download.  The URL column is assumed to be valid.
-         * @return The status of the download.
+         * Query where clause by app data.
          * @hide
          */
-        private static final int getStatusOfDownload(
-                Cursor c,
-                long redownload_threshold) {
-            int status = c.getInt(DOWNLOADS_COLUMN_STATUS);
-            long realtime = SystemClock.elapsedRealtime();
-
-            // TODO(dougz): special handling of 503, 404?  (eg, special
-            // explanatory messages to user)
-
-            if (!android.provider.Downloads.Impl.isStatusCompleted(status)) {
-                // Check if it's stuck
-                long modified = c.getLong(DOWNLOADS_COLUMN_LAST_MODIFICATION);
-                long now = System.currentTimeMillis();
-                if (now < modified || now - modified > redownload_threshold) {
-                    return STATUS_INVALID;
-                }
-
-                return STATUS_DOWNLOADING_UPDATE;
-            }
-
-            if (android.provider.Downloads.Impl.isStatusError(status)) {
-                return STATUS_INVALID;
-            }
-
-            String filename = c.getString(DOWNLOADS_COLUMN_FILENAME);
-            if (filename == null) {
-                return STATUS_INVALID;
-            }
-
-            return STATUS_DOWNLOADED_UPDATE;
-        }
+        private static final String QUERY_WHERE_APP_DATA_CLAUSE =
+                android.provider.Downloads.Impl.COLUMN_APP_DATA + "=?";
 
         /**
          * Gets a Cursor pointing to the download(s) of the current system update.
@@ -190,15 +222,14 @@
             return context.getContentResolver().query(
                     android.provider.Downloads.Impl.CONTENT_URI,
                     DOWNLOADS_PROJECTION,
-                    android.provider.Downloads.Impl.COLUMN_APP_DATA + "='" + url.replace("'", "''") + "'",
-                    null,
+                    QUERY_WHERE_APP_DATA_CLAUSE,
+                    new String[] {url},
                     null);
         }
 
         /**
          * Returns a StatusInfo with the result of trying to download the
          * given URL.  Returns null if no attempts have been made.
-         * @pending
          */
         public static final StatusInfo getStatus(
                 Context context,
@@ -237,14 +268,15 @@
                     result.bytesSoFar = c.getLong(DOWNLOADS_COLUMN_CURRENT_BYTES);
                 }
             } finally {
-                c.close();
+                if (c != null) {
+                    c.close();
+                }
             }
             return result;
         }
 
         /**
          * Query where clause for general querying.
-         * @hide
          */
         private static final String QUERY_WHERE_CLAUSE =
                 android.provider.Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + "=? AND " +
@@ -252,7 +284,6 @@
 
         /**
          * Delete all the downloads for a package/class pair.
-         * @pending
          */
         public static final void removeAllDownloadsByPackage(
                 Context context,
@@ -265,21 +296,24 @@
         }
 
         /**
-         * @pending
+         * The column for the id in the Cursor returned by
+         * getProgressCursor()
          */
         public static final int getProgressColumnId() {
             return 0;
         }
 
         /**
-         * @pending
+         * The column for the current byte count in the Cursor returned by
+         * getProgressCursor()
          */
         public static final int getProgressColumnCurrentBytes() {
             return 1;
         }
 
         /**
-         * @pending
+         * The column for the total byte count in the Cursor returned by
+         * getProgressCursor()
          */
         public static final int getProgressColumnTotalBytes() {
             return 2;
@@ -287,19 +321,324 @@
 
         /** @hide */
         private static final String[] PROJECTION = {
-            BaseColumns._ID, android.provider.Downloads.Impl.COLUMN_CURRENT_BYTES, android.provider.Downloads.Impl.COLUMN_TOTAL_BYTES
+            BaseColumns._ID,
+            android.provider.Downloads.Impl.COLUMN_CURRENT_BYTES,
+            android.provider.Downloads.Impl.COLUMN_TOTAL_BYTES
         };
 
         /**
-         * @pending
+         * Returns a Cursor representing the progress of the download identified by the ID.
          */
         public static final Cursor getProgressCursor(Context context, long id) {
-            Uri downloadUri = Uri.withAppendedPath(android.provider.Downloads.Impl.CONTENT_URI, String.valueOf(id));
+            Uri downloadUri = Uri.withAppendedPath(android.provider.Downloads.Impl.CONTENT_URI,
+                    String.valueOf(id));
             return context.getContentResolver().query(downloadUri, PROJECTION, null, null, null);
         }
     }
 
     /**
+     * Class to access downloads by opaque download id
+     */
+    public static final class ById extends DownloadBase {
+        /** @hide */
+        private ById() {}
+
+        /**
+         * Get the mime tupe of the download specified by the download id
+         */
+        public static String getMimeTypeForId(Context context, long downloadId) {
+            ContentResolver cr = context.getContentResolver();
+
+            String mimeType = null;
+            Cursor downloadCursor = null;
+
+            try {
+                Uri downloadUri = getDownloadUri(downloadId);
+
+                downloadCursor = cr.query(
+                        downloadUri, new String[]{android.provider.Downloads.Impl.COLUMN_MIME_TYPE},
+                        null, null, null);
+                if (downloadCursor.moveToNext()) {
+                    mimeType = downloadCursor.getString(0);
+                }
+            } finally {
+                if (downloadCursor != null) downloadCursor.close();
+            }
+            return mimeType;
+        }
+
+        /**
+         * Delete a download by Id
+         */
+        public static void deleteDownload(Context context, long downloadId) {
+            ContentResolver cr = context.getContentResolver();
+
+            String mimeType = null;
+
+            Uri downloadUri = getDownloadUri(downloadId);
+
+            cr.delete(downloadUri, null, null);
+        }
+
+        /**
+         * Open a filedescriptor to a particular download
+         */
+        public static ParcelFileDescriptor openDownload(
+                Context context, long downloadId, String mode)
+            throws FileNotFoundException
+        {
+            ContentResolver cr = context.getContentResolver();
+
+            String mimeType = null;
+
+            Uri downloadUri = getDownloadUri(downloadId);
+
+            return cr.openFileDescriptor(downloadUri, mode);
+        }
+
+        /**
+         * Open a stream to a particular download
+         */
+        public static InputStream openDownloadStream(Context context, long downloadId)
+                throws FileNotFoundException, IOException
+        {
+            ContentResolver cr = context.getContentResolver();
+
+            String mimeType = null;
+
+            Uri downloadUri = getDownloadUri(downloadId);
+
+            return cr.openInputStream(downloadUri);
+        }
+
+        private static Uri getDownloadUri(long downloadId) {
+            return Uri.parse(android.provider.Downloads.Impl.CONTENT_URI + "/" + downloadId);
+        }
+
+        /**
+         * Returns a StatusInfo with the result of trying to download the
+         * given URL.  Returns null if no attempts have been made.
+         */
+        public static final StatusInfo getStatus(
+                Context context,
+                long downloadId) {
+            StatusInfo result = null;
+            boolean hasFailedDownload = false;
+            long failedDownloadModificationTime = 0;
+
+            Uri downloadUri = getDownloadUri(downloadId);
+
+            ContentResolver cr = context.getContentResolver();
+
+            Cursor c = cr.query(
+                    downloadUri, DOWNLOADS_PROJECTION, null /* selection */, null /* selection args */,
+                    null /* sort order */);
+            try {
+                if (!c.moveToNext()) {
+                    return result;
+                }
+
+                if (result == null) {
+                    result = new StatusInfo();
+                }
+                int status = getStatusOfDownload(c,0);
+                if (status == STATUS_DOWNLOADING_UPDATE ||
+                        status == STATUS_DOWNLOADED_UPDATE) {
+                    result.completed = (status == STATUS_DOWNLOADED_UPDATE);
+                    result.filename = c.getString(DOWNLOADS_COLUMN_FILENAME);
+                    result.id = c.getLong(DOWNLOADS_COLUMN_ID);
+                    result.statusCode = c.getInt(DOWNLOADS_COLUMN_STATUS);
+                    result.bytesSoFar = c.getLong(DOWNLOADS_COLUMN_CURRENT_BYTES);
+                    return result;
+                }
+
+                long modTime = c.getLong(DOWNLOADS_COLUMN_LAST_MODIFICATION);
+
+                result.statusCode = c.getInt(DOWNLOADS_COLUMN_STATUS);
+                result.bytesSoFar = c.getLong(DOWNLOADS_COLUMN_CURRENT_BYTES);
+            } finally {
+                if (c != null) {
+                    c.close();
+                }
+            }
+            return result;
+        }
+    }
+
+
+    /**
+     * Base class with common functionality for the various download classes
+     */
+    private static class DownloadBase {
+        /** @hide */
+        DownloadBase() {}
+
+        /**
+          * Initiate a download where the download will be tracked by its URI.
+          */
+        public static long startDownloadByUri(
+                Context context,
+                String url,
+                String cookieData,
+                boolean showDownload,
+                int downloadDestination,
+                boolean allowRoaming,
+                boolean skipIntegrityCheck,
+                String title,
+                String notification_package,
+                String notification_class,
+                String notification_extras) {
+            ContentResolver cr = context.getContentResolver();
+
+            // Tell download manager to start downloading update.
+            ContentValues values = new ContentValues();
+            values.put(android.provider.Downloads.Impl.COLUMN_URI, url);
+            values.put(android.provider.Downloads.Impl.COLUMN_COOKIE_DATA, cookieData);
+            values.put(android.provider.Downloads.Impl.COLUMN_VISIBILITY,
+                       showDownload ? android.provider.Downloads.Impl.VISIBILITY_VISIBLE
+                       : android.provider.Downloads.Impl.VISIBILITY_HIDDEN);
+            if (title != null) {
+                values.put(android.provider.Downloads.Impl.COLUMN_TITLE, title);
+            }
+            values.put(android.provider.Downloads.Impl.COLUMN_APP_DATA, url);
+
+
+            // NOTE:  destination should be seperated from whether the download
+            // can happen when roaming
+            int destination = android.provider.Downloads.Impl.DESTINATION_EXTERNAL;
+            switch (downloadDestination) {
+                case DOWNLOAD_DESTINATION_EXTERNAL:
+                    destination = android.provider.Downloads.Impl.DESTINATION_EXTERNAL;
+                    break;
+                case DOWNLOAD_DESTINATION_CACHE:
+                    if (allowRoaming) {
+                        destination = android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION;
+                    } else {
+                        destination =
+                                android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING;
+                    }
+                    break;
+                case DOWNLOAD_DESTINATION_CACHE_PURGEABLE:
+                    destination =
+                            android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE;
+                    break;
+            }
+            values.put(android.provider.Downloads.Impl.COLUMN_DESTINATION, destination);
+            values.put(android.provider.Downloads.Impl.COLUMN_NO_INTEGRITY,
+                    skipIntegrityCheck);  // Don't check ETag
+            if (notification_package != null && notification_class != null) {
+                values.put(android.provider.Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
+                        notification_package);
+                values.put(android.provider.Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
+                        notification_class);
+
+                if (notification_extras != null) {
+                    values.put(android.provider.Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS,
+                            notification_extras);
+                }
+            }
+
+            Uri downloadUri = cr.insert(android.provider.Downloads.Impl.CONTENT_URI, values);
+
+            long downloadId = DOWNLOAD_ID_INVALID;
+            if (downloadUri != null) {
+                downloadId = Long.parseLong(downloadUri.getLastPathSegment());
+            }
+            return downloadId;
+        }
+    }
+
+    /** @hide */
+    private static final int STATUS_INVALID = 0;
+    /** @hide */
+    private static final int STATUS_DOWNLOADING_UPDATE = 3;
+    /** @hide */
+    private static final int STATUS_DOWNLOADED_UPDATE = 4;
+
+    /**
+     * Column projection for the query to the download manager. This must match
+     * with the constants DOWNLOADS_COLUMN_*.
+     * @hide
+     */
+    private static final String[] DOWNLOADS_PROJECTION = {
+            BaseColumns._ID,
+            android.provider.Downloads.Impl.COLUMN_APP_DATA,
+            android.provider.Downloads.Impl.COLUMN_STATUS,
+            android.provider.Downloads.Impl._DATA,
+            android.provider.Downloads.Impl.COLUMN_LAST_MODIFICATION,
+            android.provider.Downloads.Impl.COLUMN_CURRENT_BYTES,
+    };
+
+    /**
+     * The column index for the ID.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_ID = 0;
+    /**
+     * The column index for the URI.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_URI = 1;
+    /**
+     * The column index for the status code.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_STATUS = 2;
+    /**
+     * The column index for the filename.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_FILENAME = 3;
+    /**
+     * The column index for the last modification time.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_LAST_MODIFICATION = 4;
+    /**
+     * The column index for the number of bytes downloaded so far.
+     * @hide
+     */
+    private static final int DOWNLOADS_COLUMN_CURRENT_BYTES = 5;
+
+    /**
+     * Gets the status of a download.
+     *
+     * @param c A Cursor pointing to a download.  The URL column is assumed to be valid.
+     * @return The status of the download.
+     * @hide
+     */
+    private static final int getStatusOfDownload( Cursor c, long redownload_threshold) {
+        int status = c.getInt(DOWNLOADS_COLUMN_STATUS);
+        long realtime = SystemClock.elapsedRealtime();
+
+        // TODO(dougz): special handling of 503, 404?  (eg, special
+        // explanatory messages to user)
+
+        if (!android.provider.Downloads.Impl.isStatusCompleted(status)) {
+            // Check if it's stuck
+            long modified = c.getLong(DOWNLOADS_COLUMN_LAST_MODIFICATION);
+            long now = System.currentTimeMillis();
+            if (now < modified || now - modified > redownload_threshold) {
+                return STATUS_INVALID;
+            }
+
+            return STATUS_DOWNLOADING_UPDATE;
+        }
+
+        if (android.provider.Downloads.Impl.isStatusError(status)) {
+            return STATUS_INVALID;
+        }
+
+        String filename = c.getString(DOWNLOADS_COLUMN_FILENAME);
+        if (filename == null) {
+            return STATUS_INVALID;
+        }
+
+        return STATUS_DOWNLOADED_UPDATE;
+    }
+
+
+    /**
      * @hide
      */
     private Downloads() {}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index ed76b15..f959fee 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -50,12 +50,14 @@
  * <ul>
  * <li>Timeout specification for SSL handshake operations
  * <li>Optional SSL session caching with {@link SSLSessionCache}
- * <li>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
- * SSL certificate checks, for testing with development servers
+ * <li>Optionally bypass all SSL certificate checks
  * </ul>
  * Note that the handshake timeout does not apply to actual connection.
  * If you want a connection timeout as well, use {@link #createSocket()} and
  * {@link Socket#connect(SocketAddress, int)}.
+ * <p>
+ * On development devices, "setprop socket.relaxsslcheck yes" bypasses all
+ * SSL certificate checks, for testing with development servers.
  */
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
     private static final String TAG = "SSLCertificateSocketFactory";
@@ -73,41 +75,57 @@
 
     private final int mHandshakeTimeoutMillis;
     private final SSLClientSessionCache mSessionCache;
+    private final boolean mSecure;
 
     /** @deprecated Use {@link #getDefault(int)} instead. */
     public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
-        this(handshakeTimeoutMillis, null /* cache */);
+        this(handshakeTimeoutMillis, null, true);
     }
 
-    private SSLCertificateSocketFactory(int handshakeTimeoutMillis, SSLSessionCache cache) {
+    private SSLCertificateSocketFactory(
+            int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
         mHandshakeTimeoutMillis = handshakeTimeoutMillis;
         mSessionCache = cache == null ? null : cache.mSessionCache;
+        mSecure = secure;
     }
 
     /**
-     * Returns a new instance of a socket factory using the specified socket read
-     * timeout while connecting with the server/negotiating an ssl session.
+     * Returns a new socket factory instance with an optional handshake timeout.
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
      * @return a new SocketFactory with the specified parameters
      */
     public static SocketFactory getDefault(int handshakeTimeoutMillis) {
-        return getDefault(handshakeTimeoutMillis, null /* cache */);
+        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true);
     }
 
     /**
-     * Returns a new instance of a socket factory using the specified socket
-     * read timeout while connecting with the server/negotiating an ssl session
-     * Persists ssl sessions using the provided {@link SSLClientSessionCache}.
+     * Returns a new socket factory instance with an optional handshake timeout
+     * and SSL session cache.
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
      * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
      * @return a new SocketFactory with the specified parameters
      */
-    public static SocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
-        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache);
+    public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
+        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true);
+    }
+
+    /**
+     * Returns a new instance of a socket factory with all SSL security checks
+     * disabled, using an optional handshake timeout and SSL session cache.
+     * Sockets created using this factory are vulnerable to man-in-the-middle
+     * attacks!
+     *
+     * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+     *         for none.  The socket timeout is reset to 0 after the handshake.
+     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @return an insecure SocketFactory with the specified parameters
+     */
+    public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
+        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false);
     }
 
     /**
@@ -123,7 +141,7 @@
             int handshakeTimeoutMillis,
             SSLSessionCache cache) {
         return new org.apache.http.conn.ssl.SSLSocketFactory(
-                new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache));
+                new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
     }
 
     private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
@@ -138,12 +156,15 @@
     }
 
     private synchronized SSLSocketFactory getDelegate() {
-        // only allow relaxing the ssl check on non-secure builds where the relaxation is
-        // specifically requested.
-        if ("0".equals(SystemProperties.get("ro.secure")) &&
-            "yes".equals(SystemProperties.get("socket.relaxsslcheck"))) {
+        // Relax the SSL check if instructed (for this factory, or systemwide)
+        if (!mSecure || ("0".equals(SystemProperties.get("ro.secure")) &&
+            "yes".equals(SystemProperties.get("socket.relaxsslcheck")))) {
             if (mInsecureFactory == null) {
-                Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
+                if (mSecure) {
+                    Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
+                } else {
+                    Log.w(TAG, "Bypassing SSL security checks at caller's request");
+                }
                 mInsecureFactory = makeSocketFactory(INSECURE_TRUST_MANAGER);
             }
             return mInsecureFactory;
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index f4ae66a..fa13894 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static com.android.common.Patterns.GOOD_IRI_CHAR;
+
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -54,9 +56,10 @@
     static Pattern sAddressPattern = Pattern.compile(
             /* scheme    */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
             /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
-            /* host      */ "([-A-Za-z0-9%_]+(?:\\.[-A-Za-z0-9%_]+)*|\\[[0-9a-fA-F:\\.]+\\])?" +
+            /* host      */ "([-" + GOOD_IRI_CHAR + "%_]+(?:\\.[-" + GOOD_IRI_CHAR + "%_]+)*|\\[[0-9a-fA-F:\\.]+\\])?" +
             /* port      */ "(?:\\:([0-9]+))?" +
-            /* path      */ "(\\/?.*)?");
+            /* path      */ "(\\/?[^#]*)?" +
+            /* anchor    */ ".*");
 
     /** parses given uriString. */
     public WebAddress(String address) throws ParseException {
diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl
deleted file mode 100644
index 37af496..0000000
--- a/core/java/android/os/ICheckinService.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2007 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.os;
-
-import android.os.IParentalControlCallback;
-
-/**
- * System private API for direct access to the checkin service.
- * Users should use the content provider instead.
- *
- * @see android.provider.Checkin
- * {@hide}
- */
-interface ICheckinService {
-    /**
-     * Determine if the device is under parental control. Return null if
-     * we are unable to check the parental control status.
-     */
-    void getParentalControlState(IParentalControlCallback p,
-                                 String requestingApp);
-}
diff --git a/core/java/android/os/IParentalControlCallback.aidl b/core/java/android/os/IParentalControlCallback.aidl
deleted file mode 100644
index 2f1a563..0000000
--- a/core/java/android/os/IParentalControlCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2008 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.os;
-
-import com.google.android.net.ParentalControlState;
-
-/**
- * This callback interface is used to deliver the parental control state to the calling application.
- * {@hide}
- */
-oneway interface IParentalControlCallback {
-	void onResult(in ParentalControlState state);
-}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 389c9f4..2eb25954 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -25,11 +25,13 @@
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.os.RemoteException;
+import android.pim.vcard.exception.VCardException;
 import android.provider.CallLog;
 import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.RawContactsEntity;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -54,6 +56,7 @@
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
@@ -199,6 +202,10 @@
                 try {
                     // Create one empty entry.
                     mWriter.write(createOneEntryInternal("-1", null));
+                } catch (VCardException e) {
+                    Log.e(LOG_TAG, "VCardException has been thrown during on Init(): " +
+                            e.getMessage());
+                    return false;
                 } catch (IOException e) {
                     Log.e(LOG_TAG,
                             "IOException occurred during exportOneContactData: "
@@ -455,6 +462,9 @@
                     return true;
                 }
             }
+        } catch (VCardException e) {
+            Log.e(LOG_TAG, "VCardException has been thrown: " + e.getMessage());
+            return false;
         } catch (OutOfMemoryError error) {
             // Maybe some data (e.g. photo) is too big to have in memory. But it
             // should be rare.
@@ -486,36 +496,42 @@
     }
 
     private String createOneEntryInternal(final String contactId,
-            Method getEntityIteratorMethod) {
+            Method getEntityIteratorMethod) throws VCardException {
         final Map<String, List<ContentValues>> contentValuesListMap =
                 new HashMap<String, List<ContentValues>>();
-        // The resolver may return the entity iterator with no data. It is possiible.
+        // The resolver may return the entity iterator with no data. It is possible.
         // e.g. If all the data in the contact of the given contact id are not exportable ones,
         //      they are hidden from the view of this method, though contact id itself exists.
-        boolean dataExists = false;
         EntityIterator entityIterator = null;
         try {
-
+            final Uri uri = RawContactsEntity.CONTENT_URI.buildUpon()
+                    .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
+                    .build();
+            final String selection = Data.CONTACT_ID + "=?";
+            final String[] selectionArgs = new String[] {contactId};
             if (getEntityIteratorMethod != null) {
+                // Please note that this branch is executed by some tests only
                 try {
-                    final Uri uri = RawContacts.CONTENT_URI.buildUpon()
-                            .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
-                            .build();
-                    final String selection = Data.CONTACT_ID + "=?";
-                    final String[] selectionArgs = new String[] {contactId};
                     entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
                             mContentResolver, uri, selection, selectionArgs, null);
-                } catch (Exception e) {
-                    e.printStackTrace();
+                } catch (IllegalArgumentException e) {
+                    Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
+                            e.getMessage());
+                } catch (IllegalAccessException e) {
+                    Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
+                            e.getMessage());
+                } catch (InvocationTargetException e) {
+                    Log.e(LOG_TAG, "InvocationTargetException has been thrown: ");
+                    StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
+                    for (StackTraceElement element : stackTraceElements) {
+                        Log.e(LOG_TAG, "    at " + element.toString());
+                    }
+                    throw new VCardException("InvocationTargetException has been thrown: " +
+                            e.getCause().getMessage());
                 }
             } else {
-                final Uri uri = RawContacts.CONTENT_URI.buildUpon()
-                        .appendEncodedPath(contactId)
-                        .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
-                        .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
-                        .build();
                 entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
-                        uri, null, null, null, null));
+                        uri, null, selection, selectionArgs, null));
             }
 
             if (entityIterator == null) {
@@ -523,7 +539,11 @@
                 return "";
             }
 
-            dataExists = entityIterator.hasNext();
+            if (!entityIterator.hasNext()) {
+                Log.w(LOG_TAG, "Data does not exist. contactId: " + contactId);
+                return "";
+            }
+
             while (entityIterator.hasNext()) {
                 Entity entity = entityIterator.next();
                 for (NamedContentValues namedContentValues : entity.getSubValues()) {
@@ -550,10 +570,6 @@
             }
         }
 
-        if (!dataExists) {
-            return "";
-        }
-
         final VCardBuilder builder = new VCardBuilder(mVCardType);
         builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
                 .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java
index 20eee84..1cf3144 100644
--- a/core/java/android/pim/vcard/VCardEntry.java
+++ b/core/java/android/pim/vcard/VCardEntry.java
@@ -281,6 +281,29 @@
                     isPrimary == organization.isPrimary);
         }
 
+        public String getFormattedString() {
+            final StringBuilder builder = new StringBuilder();
+            if (!TextUtils.isEmpty(companyName)) {
+                builder.append(companyName);
+            }
+
+            if (!TextUtils.isEmpty(departmentName)) {
+                if (builder.length() > 0) {
+                    builder.append(", ");
+                }
+                builder.append(departmentName);
+            }
+
+            if (!TextUtils.isEmpty(titleName)) {
+                if (builder.length() > 0) {
+                    builder.append(", ");
+                }
+                builder.append(titleName);
+            }
+
+            return builder.toString();
+        }
+
         @Override
         public String toString() {
             return String.format(
@@ -1008,6 +1031,8 @@
             mDisplayName = mPhoneList.get(0).data;
         } else if (mPostalList != null && mPostalList.size() > 0) {
             mDisplayName = mPostalList.get(0).getFormattedAddress(mVCardType);
+        } else if (mOrganizationList != null && mOrganizationList.size() > 0) {
+            mDisplayName = mOrganizationList.get(0).getFormattedString();
         }
 
         if (mDisplayName == null) {
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
deleted file mode 100644
index 75936a1..0000000
--- a/core/java/android/provider/Checkin.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2006 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.provider;
-
-import org.apache.commons.codec.binary.Base64;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.SQLException;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-
-/**
- * Contract class for the checkin provider, used to store events and
- * statistics that will be uploaded to a checkin server eventually.
- * Describes the exposed database schema, and offers methods to add
- * events and statistics to be uploaded.
- *
- * TODO: Move this to vendor/google when we have a home for it.
- *
- * @hide
- */
-public final class Checkin {
-    public static final String AUTHORITY = "android.server.checkin";
-
-    /**
-     * The events table is a log of important timestamped occurrences.
-     * Each event has a type tag and an optional string value.
-     * If too many events are added before they can be reported, the
-     * content provider will erase older events to limit the table size.
-     */
-    public interface Events extends BaseColumns {
-        public static final String TABLE_NAME = "events";
-        public static final Uri CONTENT_URI =
-            Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
-
-        public static final String TAG = "tag";     // TEXT
-        public static final String VALUE = "value"; // TEXT
-        public static final String DATE = "date";   // INTEGER
-
-        /** Valid tag values.  Extend as necessary for your needs. */
-        public enum Tag {
-            APANIC_CONSOLE,
-            APANIC_THREADS,
-            AUTOTEST_FAILURE,
-            AUTOTEST_SEQUENCE_BEGIN,
-            AUTOTEST_SUITE_BEGIN,
-            AUTOTEST_TCPDUMP_BEGIN,
-            AUTOTEST_TCPDUMP_DATA,
-            AUTOTEST_TCPDUMP_END,
-            AUTOTEST_TEST_BEGIN,
-            AUTOTEST_TEST_FAILURE,
-            AUTOTEST_TEST_SUCCESS,
-            BROWSER_BUG_REPORT,
-            CARRIER_BUG_REPORT,
-            CHECKIN_FAILURE,
-            CHECKIN_SUCCESS,
-            FOTA_BEGIN,
-            FOTA_FAILURE,
-            FOTA_INSTALL,
-            FOTA_PROMPT,
-            FOTA_PROMPT_ACCEPT,
-            FOTA_PROMPT_REJECT,
-            FOTA_PROMPT_SKIPPED,
-            GSERVICES_ERROR,
-            GSERVICES_UPDATE,
-            LOGIN_SERVICE_ACCOUNT_TRIED,
-            LOGIN_SERVICE_ACCOUNT_SAVED,
-            LOGIN_SERVICE_AUTHENTICATE,
-            LOGIN_SERVICE_CAPTCHA_ANSWERED,
-            LOGIN_SERVICE_CAPTCHA_SHOWN,
-            LOGIN_SERVICE_PASSWORD_ENTERED,
-            LOGIN_SERVICE_SWITCH_GOOGLE_MAIL,
-            NETWORK_DOWN,
-            NETWORK_UP,
-            PHONE_UI,
-            RADIO_BUG_REPORT,
-            SETUP_COMPLETED,
-            SETUP_INITIATED,
-            SETUP_IO_ERROR,
-            SETUP_NETWORK_ERROR,
-            SETUP_REQUIRED_CAPTCHA,
-            SETUP_RETRIES_EXHAUSTED,
-            SETUP_SERVER_ERROR,
-            SETUP_SERVER_TIMEOUT,
-            SETUP_NO_DATA_NETWORK,
-            SYSTEM_BOOT,
-            SYSTEM_LAST_KMSG,
-            SYSTEM_RECOVERY_LOG,
-            SYSTEM_RESTART,
-            SYSTEM_SERVICE_LOOPING,
-            SYSTEM_TOMBSTONE,
-            TEST, 
-            BATTERY_DISCHARGE_INFO,
-            MARKET_DOWNLOAD,
-            MARKET_INSTALL,
-            MARKET_REMOVE,
-            MARKET_REFUND,
-            MARKET_UNINSTALL,
-        }
-    }
-
-    /**
-     * The stats table is a list of counter values indexed by a tag name.
-     * Each statistic has a count and sum fields, so it can track averages.
-     * When multiple statistics are inserted with the same tag, the count
-     * and sum fields are added together into a single entry in the database.
-     */
-    public interface Stats extends BaseColumns {
-        public static final String TABLE_NAME = "stats";
-        public static final Uri CONTENT_URI =
-            Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
-
-        public static final String TAG = "tag";      // TEXT UNIQUE
-        public static final String COUNT = "count";  // INTEGER
-        public static final String SUM = "sum";      // REAL
-
-        /** Valid tag values.  Extend as necessary for your needs. */
-        public enum Tag {
-            BROWSER_SNAP_CENTER,
-            BROWSER_TEXT_SIZE_CHANGE,
-            BROWSER_ZOOM_OVERVIEW,
-
-            CRASHES_REPORTED,
-            CRASHES_TRUNCATED,
-            ELAPSED_REALTIME_SEC,
-            ELAPSED_UPTIME_SEC,
-            HTTP_REQUEST,
-            HTTP_REUSED,
-            HTTP_STATUS,
-            PHONE_GSM_REGISTERED,
-            PHONE_GPRS_ATTEMPTED,
-            PHONE_GPRS_CONNECTED,
-            PHONE_RADIO_RESETS,
-            TEST,
-            NETWORK_RX_MOBILE,
-            NETWORK_TX_MOBILE,
-            PHONE_CDMA_REGISTERED,
-            PHONE_CDMA_DATA_ATTEMPTED,
-            PHONE_CDMA_DATA_CONNECTED,
-        }
-    }
-
-    /**
-     * The properties table is a set of tagged values sent with every checkin.
-     * Unlike statistics or events, they are not cleared after being uploaded.
-     * Multiple properties inserted with the same tag overwrite each other.
-     */
-    public interface Properties extends BaseColumns {
-        public static final String TABLE_NAME = "properties";
-        public static final Uri CONTENT_URI =
-            Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
-
-        public static final String TAG = "tag";      // TEXT UNIQUE
-        public static final String VALUE = "value";  // TEXT
-
-        /** Valid tag values, to be extended as necessary. */
-        public enum Tag {
-            DESIRED_BUILD,
-            MARKET_CHECKIN,
-        }
-    }
-
-    /**
-     * The crashes table is a log of crash reports, kept separate from the
-     * general event log because crashes are large, important, and bursty.
-     * Like the events table, the crashes table is pruned on insert.
-     */
-    public interface Crashes extends BaseColumns {
-        public static final String TABLE_NAME = "crashes";
-        public static final Uri CONTENT_URI =
-            Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
-
-        // TODO: one or both of these should be a file attachment, not a column
-        public static final String DATA = "data";    // TEXT
-        public static final String LOGS = "logs";    // TEXT
-    }
-
-    /**
-     * Intents with this action cause a checkin attempt.  Normally triggered by
-     * a periodic alarm, these may be sent directly to force immediate checkin.
-     */
-    public interface TriggerIntent {
-        public static final String ACTION = "android.server.checkin.CHECKIN";
-
-        // The category is used for GTalk service messages
-        public static final String CATEGORY = "android.server.checkin.CHECKIN";
-        
-        // If true indicates that the checkin should only transfer market related data
-        public static final String EXTRA_MARKET_ONLY = "market_only";
-    }
-
-    private static final String TAG = "Checkin";
-
-    /**
-     * Helper function to log an event to the database.
-     *
-     * @param resolver from {@link android.content.Context#getContentResolver}
-     * @param tag identifying the type of event being recorded
-     * @param value associated with event, if any
-     * @return URI of the event that was added
-     */
-    static public Uri logEvent(ContentResolver resolver,
-            Events.Tag tag, String value) {
-        try {
-            // Don't specify the date column; the content provider will add that.
-            ContentValues values = new ContentValues();
-            values.put(Events.TAG, tag.toString());
-            if (value != null) values.put(Events.VALUE, value);
-            return resolver.insert(Events.CONTENT_URI, values);
-        } catch (IllegalArgumentException e) {  // thrown when provider is unavailable.
-            Log.w(TAG, "Can't log event " + tag + ": " + e);
-            return null;
-        } catch (SQLException e) {
-            Log.e(TAG, "Can't log event " + tag, e);  // Database errors are not fatal.
-            return null;
-        }
-    }
-
-    /**
-     * Helper function to update statistics in the database.
-     * Note that multiple updates to the same tag will be combined.
-     *
-     * @param tag identifying what is being observed
-     * @param count of occurrences
-     * @param sum of some value over these occurrences
-     * @return URI of the statistic that was returned
-     */
-    static public Uri updateStats(ContentResolver resolver,
-            Stats.Tag tag, int count, double sum) {
-        try {
-            ContentValues values = new ContentValues();
-            values.put(Stats.TAG, tag.toString());
-            if (count != 0) values.put(Stats.COUNT, count);
-            if (sum != 0.0) values.put(Stats.SUM, sum);
-            return resolver.insert(Stats.CONTENT_URI, values);
-        } catch (IllegalArgumentException e) {  // thrown when provider is unavailable.
-            Log.w(TAG, "Can't update stat " + tag + ": " + e);
-            return null;
-        } catch (SQLException e) {
-            Log.e(TAG, "Can't update stat " + tag, e);  // Database errors are not fatal.
-            return null;
-        }
-    }
-
-    /** Minimum time to wait after a crash failure before trying again. */
-    static private final long MIN_CRASH_FAILURE_RETRY = 10000;  // 10 seconds
-
-    /** {@link SystemClock#elapsedRealtime} of the last time a crash report failed. */
-    static private volatile long sLastCrashFailureRealtime = -MIN_CRASH_FAILURE_RETRY;
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bfab30a..7b52f7f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1497,6 +1497,66 @@
         public static final String POINTER_LOCATION = "pointer_location";
 
         /**
+         * Whether to play a sound for low-battery alerts.
+         * @hide
+         */
+        public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
+
+        /**
+         * Whether to play a sound for dock events.
+         * @hide
+         */
+        public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
+
+        /**
+         * Whether to play sounds when the keyguard is shown and dismissed.
+         * @hide
+         */
+        public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
+
+        /**
+         * URI for the low battery sound file.
+         * @hide
+         */
+        public static final String LOW_BATTERY_SOUND = "low_battery_sound";
+
+        /**
+         * URI for the desk dock "in" event sound.
+         * @hide
+         */
+        public static final String DESK_DOCK_SOUND = "desk_dock_sound";
+
+        /**
+         * URI for the desk dock "out" event sound.
+         * @hide
+         */
+        public static final String DESK_UNDOCK_SOUND = "desk_undock_sound";
+
+        /**
+         * URI for the car dock "in" event sound.
+         * @hide
+         */
+        public static final String CAR_DOCK_SOUND = "car_dock_sound";
+
+        /**
+         * URI for the car dock "out" event sound.
+         * @hide
+         */
+        public static final String CAR_UNDOCK_SOUND = "car_undock_sound";
+
+        /**
+         * URI for the "device locked" (keyguard shown) sound.
+         * @hide
+         */
+        public static final String LOCK_SOUND = "lock_sound";
+
+        /**
+         * URI for the "device unlocked" (keyguard dismissed) sound.
+         * @hide
+         */
+        public static final String UNLOCK_SOUND = "unlock_sound";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          * @hide
@@ -2150,14 +2210,17 @@
         public static final String NETWORK_PREFERENCE = "network_preference";
 
         /**
+         * No longer supported.
          */
         public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
 
         /**
+         * No longer supported.
          */
         public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
 
         /**
+         * No longer supported.
          */
         public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
 
diff --git a/core/java/android/text/AndroidCharacter.java b/core/java/android/text/AndroidCharacter.java
index 6dfd64d..af93b5d 100644
--- a/core/java/android/text/AndroidCharacter.java
+++ b/core/java/android/text/AndroidCharacter.java
@@ -22,6 +22,13 @@
  */
 public class AndroidCharacter
 {
+    public static final int EAST_ASIAN_WIDTH_NEUTRAL = 0;
+    public static final int EAST_ASIAN_WIDTH_AMBIGUOUS = 1;
+    public static final int EAST_ASIAN_WIDTH_HALF_WIDTH = 2;
+    public static final int EAST_ASIAN_WIDTH_FULL_WIDTH = 3;
+    public static final int EAST_ASIAN_WIDTH_NARROW = 4;
+    public static final int EAST_ASIAN_WIDTH_WIDE = 5;
+
     /**
      * Fill in the first <code>count</code> bytes of <code>dest</code> with the
      * directionalities from the first <code>count</code> chars of <code>src</code>.
@@ -30,6 +37,38 @@
      */
     public native static void getDirectionalities(char[] src, byte[] dest,
                                                   int count);
+
+    /**
+     * Calculate the East Asian Width of a character according to
+     * <a href="http://unicode.org/reports/tr11/">Unicode TR#11</a>. The return
+     * will be one of {@link #EAST_ASIAN_WIDTH_NEUTRAL},
+     * {@link #EAST_ASIAN_WIDTH_AMBIGUOUS}, {@link #EAST_ASIAN_WIDTH_HALF_WIDTH},
+     * {@link #EAST_ASIAN_WIDTH_FULL_WIDTH}, {@link #EAST_ASIAN_WIDTH_NARROW},
+     * or {@link #EAST_ASIAN_WIDTH_WIDE}.
+     * 
+     * @param input the character to measure
+     * @return the East Asian Width for input
+     */
+    public native static int getEastAsianWidth(char input);
+
+    /**
+     * Fill the first <code>count</code> bytes of <code>dest</code> with the
+     * East Asian Width from the first <code>count</code> chars of
+     * <code>src</code>. East Asian Width is calculated based on
+     * <a href="http://unicode.org/reports/tr11/">Unicode TR#11</a>. Each entry
+     * in <code>dest> will be one of {@link #EAST_ASIAN_WIDTH_NEUTRAL},
+     * {@link #EAST_ASIAN_WIDTH_AMBIGUOUS}, {@link #EAST_ASIAN_WIDTH_HALF_WIDTH},
+     * {@link #EAST_ASIAN_WIDTH_FULL_WIDTH}, {@link #EAST_ASIAN_WIDTH_NARROW},
+     * or {@link #EAST_ASIAN_WIDTH_WIDE}.
+     * 
+     * @param src character array of input to measure
+     * @param start first character in array to measure
+     * @param count maximum number of characters to measure
+     * @param dest byte array of results for each character in src
+     */
+    public native static void getEastAsianWidths(char[] src, int start,
+                                                 int count, byte[] dest);
+
     /**
      * Replace the specified slice of <code>text</code> with the chars'
      * right-to-left mirrors (if any), returning true if any
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index 9d8bfd9..69d745d 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -84,7 +84,7 @@
                     if (c == '"') {
                         i++;
                         break;
-                    } else if (c == '\\') {
+                    } else if (c == '\\' && i + 1 < cursor) {
                         name.append(text.charAt(i + 1));
                         i += 2;
                     } else {
@@ -110,7 +110,7 @@
                         comment.append(c);
                         level++;
                         i++;
-                    } else if (c == '\\') {
+                    } else if (c == '\\' && i + 1 < cursor) {
                         comment.append(text.charAt(i + 1));
                         i += 2;
                     } else {
diff --git a/core/java/android/util/base64/Base64.java b/core/java/android/util/base64/Base64.java
index 088de9fc..f6d3905 100644
--- a/core/java/android/util/base64/Base64.java
+++ b/core/java/android/util/base64/Base64.java
@@ -16,9 +16,13 @@
 
 package android.util.base64;
 
+import java.io.UnsupportedEncodingException;
+
 /**
- * Utilities for encoding and decoding the Base64 encoding.  See RFCs
- * 2045 and 3548.
+ * Utilities for encoding and decoding the Base64 representation of
+ * binary data.  See RFCs <a
+ * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
+ * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
  */
 public class Base64 {
     /**
@@ -27,100 +31,82 @@
     public static final int DEFAULT = 0;
 
     /**
-     * Encoder flag bit to indicate you want the padding '='
-     * characters at the end (if any) to be omitted.
+     * Encoder flag bit to omit the padding '=' characters at the end
+     * of the output (if any).
      */
     public static final int NO_PADDING = 1;
 
     /**
-     * Encoder flag bit to indicate you want all line terminators to
-     * be omitted (ie, the output will be on one long line).
+     * Encoder flag bit to omit all line terminators (i.e., the output
+     * will be on one long line).
      */
     public static final int NO_WRAP = 2;
 
     /**
-     * Encoder flag bit to indicate you want lines to be ended with
-     * CRLF instead of just LF.  Has no effect if {@code NO_WRAP} is
-     * specified as well.  
+     * Encoder flag bit to indicate lines should be terminated with a
+     * CRLF pair instead of just an LF.  Has no effect if {@code
+     * NO_WRAP} is specified as well.
      */
     public static final int CRLF = 4;
 
     /**
-     * Encoder/decoder flag bit to indicate using the "web safe"
-     * variant of Base64 (see RFC 3548 section 4) where '-' and '_'
-     * are used in place of '+' and '/'.
+     * Encoder/decoder flag bit to indicate using the "URL and
+     * filename safe" variant of Base64 (see RFC 3548 section 4) where
+     * {@code -} and {@code _} are used in place of {@code +} and
+     * {@code /}.
      */
-    public static final int WEB_SAFE = 8;
+    public static final int URL_SAFE = 8;
 
     /**
-     * Flag to pass to Base64OutputStream to indicate that it should
-     * not close the output stream it is wrapping when it itself is
-     * closed.
+     * Flag to pass to {@link Base64OutputStream} to indicate that it
+     * should not close the output stream it is wrapping when it
+     * itself is closed.
      */
     public static final int NO_CLOSE = 16;
 
     //  --------------------------------------------------------
+    //  shared code
+    //  --------------------------------------------------------
+
+    /* package */ static abstract class Coder {
+        public byte[] output;
+        public int op;
+
+        /**
+         * Encode/decode another block of input data.  this.output is
+         * provided by the caller, and must be big enough to hold all
+         * the coded data.  On exit, this.opwill be set to the length
+         * of the coded data.
+         *
+         * @param finish true if this is the final call to process for
+         *        this object.  Will finalize the coder state and
+         *        include any final bytes in the output.
+         *
+         * @return true if the input so far is good; false if some
+         *         error has been detected in the input stream..
+         */
+        public abstract boolean process(byte[] input, int offset, int len, boolean finish);
+
+        /**
+         * @return the maximum number of bytes a call to process()
+         * could produce for the given number of input bytes.  This may
+         * be an overestimate.
+         */
+        public abstract int maxOutputSize(int len);
+    }
+
+    //  --------------------------------------------------------
     //  decoding
     //  --------------------------------------------------------
 
     /**
-     * Lookup table for turning bytes into their position in the
-     * Base64 alphabet.
-     */
-    private static final int DECODE[] = {
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
-        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    };
-
-    /**
-     * Decode lookup table for the "web safe" variant (RFC 3548
-     * sec. 4) where - and _ replace + and /.
-     */
-    private static final int DECODE_WEBSAFE[] = {
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
-        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
-        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    };
-
-    /** Non-data values in the DECODE arrays. */
-    private static final int SKIP = -1;
-    private static final int EQUALS = -2;
-
-    /**
      * Decode the Base64-encoded data in input and return the data in
      * a new byte array.
      *
-     * The padding '=' characters at the end are considered optional, but
+     * <p>The padding '=' characters at the end are considered optional, but
      * if any are present, there must be the correct number of them.
      *
-     * @param input the input String to decode, which is converted to
+     * @param str    the input String to decode, which is converted to
      *               bytes using the default charset
      * @param flags  controls certain features of the decoded output.
      *               Pass {@code DEFAULT} to decode standard Base64.
@@ -136,7 +122,7 @@
      * Decode the Base64-encoded data in input and return the data in
      * a new byte array.
      *
-     * The padding '=' characters at the end are considered optional, but
+     * <p>The padding '=' characters at the end are considered optional, but
      * if any are present, there must be the correct number of them.
      *
      * @param input the input array to decode
@@ -154,7 +140,7 @@
      * Decode the Base64-encoded data in input and return the data in
      * a new byte array.
      *
-     * The padding '=' characters at the end are considered optional, but
+     * <p>The padding '=' characters at the end are considered optional, but
      * if any are present, there must be the correct number of them.
      *
      * @param input  the data to decode
@@ -169,121 +155,172 @@
     public static byte[] decode(byte[] input, int offset, int len, int flags) {
         // Allocate space for the most data the input could represent.
         // (It could contain less if it contains whitespace, etc.)
-        DecoderState state = new DecoderState(flags, new byte[len*3/4]);
+        Decoder decoder = new Decoder(flags, new byte[len*3/4]);
 
-        if (!decodeInternal(input, offset, len, state, true)) {
+        if (!decoder.process(input, offset, len, true)) {
             throw new IllegalArgumentException("bad base-64");
         }
 
         // Maybe we got lucky and allocated exactly enough output space.
-        if (state.op == state.output.length) {
-            return state.output;
+        if (decoder.op == decoder.output.length) {
+            return decoder.output;
         }
 
         // Need to shorten the array, so allocate a new one of the
         // right size and copy.
-        byte[] temp = new byte[state.op];
-        System.arraycopy(state.output, 0, temp, 0, state.op);
+        byte[] temp = new byte[decoder.op];
+        System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
         return temp;
     }
 
-    /* package */ static class DecoderState {
-        public byte[] output;
-        public int op;
+    /* package */ static class Decoder extends Coder {
+        /**
+         * Lookup table for turning bytes into their position in the
+         * Base64 alphabet.
+         */
+        private static final int DECODE[] = {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        };
 
-        public int state;   // state number (0 to 6)
-        public int value;
+        /**
+         * Decode lookup table for the "web safe" variant (RFC 3548
+         * sec. 4) where - and _ replace + and /.
+         */
+        private static final int DECODE_WEBSAFE[] = {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        };
 
-        final public int[] alphabet;
+        /** Non-data values in the DECODE arrays. */
+        private static final int SKIP = -1;
+        private static final int EQUALS = -2;
 
-        public DecoderState(int flags, byte[] output) {
+        /**
+         * States 0-3 are reading through the next input tuple.
+         * State 4 is having read one '=' and expecting exactly
+         * one more.
+         * State 5 is expecting no more data or padding characters
+         * in the input.
+         * State 6 is the error state; an error has been detected
+         * in the input and no future input can "fix" it.
+         */
+        private int state;   // state number (0 to 6)
+        private int value;
+
+        final private int[] alphabet;
+
+        public Decoder(int flags, byte[] output) {
             this.output = output;
 
-            alphabet = ((flags & WEB_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
+            alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
             state = 0;
             value = 0;
         }
-    }
 
-    /**
-     * Decode another block of input data.
-     *
-     * @param dstate a DecoderState object whose (caller-provided)
-     *        output array is big enough to hold all the decoded data.
-     *        On return, dstate.op will be set to the length of the
-     *        decoded data.
-     * @param finish true if this is the final call to decodeInternal
-     *        with the given DecoderState object.  Will finalize the
-     *        decoder state and include any final bytes in the output.
-     *
-     * @return true if the state machine is still healthy.  false if
-     *         bad base-64 data has been detected in the input stream.
-     */
+        /**
+         * @return an overestimate for the number of bytes {@code
+         * len} bytes could decode to.
+         */
+        public int maxOutputSize(int len) {
+            return len * 3/4 + 10;
+        }
 
-    /* package */ static boolean decodeInternal(
-        byte[] input, int offset, int len, final DecoderState dstate, boolean finish) {
-        if (dstate.state == 6) return false;
+        /**
+         * Decode another block of input data.
+         *
+         * @return true if the state machine is still healthy.  false if
+         *         bad base-64 data has been detected in the input stream.
+         */
+        public boolean process(byte[] input, int offset, int len, boolean finish) {
+            if (this.state == 6) return false;
 
-        int state = dstate.state;
-        int value = dstate.value;
-        final int[] decode = dstate.alphabet;
-        final byte[] output = dstate.output;
-        int op = 0;
+            int p = offset;
+            len += offset;
 
-        int p = offset;
-        len += offset;
+            // Using local variables makes the decoder about 12%
+            // faster than if we manipulate the member variables in
+            // the loop.  (Even alphabet makes a measurable
+            // difference, which is somewhat surprising to me since
+            // the member variable is final.)
+            int state = this.state;
+            int value = this.value;
+            int op = 0;
+            final byte[] output = this.output;
+            final int[] alphabet = this.alphabet;
 
-        while (p < len) {
+            while (p < len) {
+                // Try the fast path:  we're starting a new tuple and the
+                // next four bytes of the input stream are all data
+                // bytes.  This corresponds to going through states
+                // 0-1-2-3-0.  We expect to use this method for most of
+                // the data.
+                //
+                // If any of the next four bytes of input are non-data
+                // (whitespace, etc.), value will end up negative.  (All
+                // the non-data values in decode are small negative
+                // numbers, so shifting any of them up and or'ing them
+                // together will result in a value with its top bit set.)
+                //
+                // You can remove this whole block and the output should
+                // be the same, just slower.
+                if (state == 0) {
+                    while (p+4 <= len &&
+                           (value = ((alphabet[input[p] & 0xff] << 18) |
+                                     (alphabet[input[p+1] & 0xff] << 12) |
+                                     (alphabet[input[p+2] & 0xff] << 6) |
+                                     (alphabet[input[p+3] & 0xff]))) >= 0) {
+                        output[op+2] = (byte) value;
+                        output[op+1] = (byte) (value >> 8);
+                        output[op] = (byte) (value >> 16);
+                        op += 3;
+                        p += 4;
+                    }
+                    if (p >= len) break;
+                }
 
-            // Try the fast path:  we're starting a new tuple and the
-            // next four bytes of the input stream are all data
-            // bytes.  This corresponds to going through states
-            // 0-1-2-3-0.  We expect to use this method for most of
-            // the data.
-            //
-            // If any of the next four bytes of input are non-data
-            // (whitespace, etc.), value will end up negative.  (All
-            // the non-data values in decode are small negative
-            // numbers, so shifting any of them up and or'ing them
-            // together will result in a value with its top bit set.)
-            //
-            // You can remove this whole block and the output should
-            // be the same, just slower.
-            if (state == 0 && p+4 <= len &&
-                (value = ((decode[input[p] & 0xff] << 18) |
-                          (decode[input[p+1] & 0xff] << 12) |
-                          (decode[input[p+2] & 0xff] << 6) |
-                          (decode[input[p+3] & 0xff]))) >= 0) {
-                output[op+2] = (byte) value;
-                output[op+1] = (byte) (value >> 8);
-                output[op] = (byte) (value >> 16);
-                op += 3;
-                p += 4;
-                continue;
-            }
+                // The fast path isn't available -- either we've read a
+                // partial tuple, or the next four input bytes aren't all
+                // data, or whatever.  Fall back to the slower state
+                // machine implementation.
 
-            // The fast path isn't available -- either we've read a
-            // partial tuple, or the next four input bytes aren't all
-            // data, or whatever.  Fall back to the slower state
-            // machine implementation.
-            //
-            // States 0-3 are reading through the next input tuple.
-            // State 4 is having read one '=' and expecting exactly
-            // one more.
-            // State 5 is expecting no more data or padding characters
-            // in the input.
-            // State 6 is the error state; an error has been detected
-            // in the input and no future input can "fix" it.
+                int d = alphabet[input[p++] & 0xff];
 
-            int d = decode[input[p++] & 0xff];
-
-            switch (state) {
+                switch (state) {
                 case 0:
                     if (d >= 0) {
                         value = d;
                         ++state;
                     } else if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
@@ -293,7 +330,7 @@
                         value = (value << 6) | d;
                         ++state;
                     } else if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
@@ -308,7 +345,7 @@
                         output[op++] = (byte) (value >> 4);
                         state = 4;
                     } else if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
@@ -330,7 +367,7 @@
                         op += 2;
                         state = 5;
                     } else if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
@@ -339,41 +376,40 @@
                     if (d == EQUALS) {
                         ++state;
                     } else if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
 
                 case 5:
                     if (d != SKIP) {
-                        dstate.state = 6;
+                        this.state = 6;
                         return false;
                     }
                     break;
+                }
             }
-        }
 
-        if (!finish) {
-            // We're out of input, but a future call could provide
-            // more.  Return the output we've produced on this call
-            // and save the current state of the state machine.
-            dstate.state = state;
-            dstate.value = value;
-            dstate.op = op;
-            return true;
-        }
+            if (!finish) {
+                // We're out of input, but a future call could provide
+                // more.
+                this.state = state;
+                this.value = value;
+                this.op = op;
+                return true;
+            }
 
-        // Done reading input.  Now figure out where we are left in
-        // the state machine and finish up.
+            // Done reading input.  Now figure out where we are left in
+            // the state machine and finish up.
 
-        switch (state) {
+            switch (state) {
             case 0:
                 // Output length is a multiple of three.  Fine.
                 break;
             case 1:
                 // Read one extra input byte, which isn't enough to
                 // make another output byte.  Illegal.
-                dstate.state = 6;
+                this.state = 6;
                 return false;
             case 2:
                 // Read two extra input bytes, enough to emit 1 more
@@ -383,22 +419,23 @@
             case 3:
                 // Read three extra input bytes, enough to emit 2 more
                 // output bytes.  Fine.
-                output[op+1] = (byte) (value >> 2);
-                output[op] = (byte) (value >> 10);
-                op += 2;
+                output[op++] = (byte) (value >> 10);
+                output[op++] = (byte) (value >> 2);
                 break;
             case 4:
                 // Read one padding '=' when we expected 2.  Illegal.
-                dstate.state = 6;
+                this.state = 6;
                 return false;
             case 5:
                 // Read all the padding '='s we expected and no more.
                 // Fine.
                 break;
-        }
+            }
 
-        dstate.op = op;
-        return true;
+            this.state = state;
+            this.op = op;
+            return true;
+        }
     }
 
     //  --------------------------------------------------------
@@ -406,43 +443,6 @@
     //  --------------------------------------------------------
 
     /**
-     * Emit a new line every this many output tuples.  Corresponds to
-     * a 76-character line length (the maximum allowable according to
-     * RFC 2045).
-     */
-    private static final int LINE_GROUPS = 19;
-
-    /**
-     * Lookup table for turning Base64 alphabet positions (6 bits)
-     * into output bytes.
-     */
-    private static final byte ENCODE[] = {
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-        'w', 'x', 'y', 'z', '0', '1', '2', '3',
-        '4', '5', '6', '7', '8', '9', '+', '/',
-    };
-
-    /**
-     * Lookup table for turning Base64 alphabet positions (6 bits)
-     * into output bytes.
-     */
-    private static final byte ENCODE_WEBSAFE[] = {
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-        'w', 'x', 'y', 'z', '0', '1', '2', '3',
-        '4', '5', '6', '7', '8', '9', '-', '_',
-    };
-
-    /**
      * Base64-encode the given data and return a newly allocated
      * String with the result.
      *
@@ -452,7 +452,12 @@
      *               adheres to RFC 2045.
      */
     public static String encodeToString(byte[] input, int flags) {
-        return new String(encode(input, flags));
+        try {
+            return new String(encode(input, flags), "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            // US-ASCII is guaranteed to be available.
+            throw new AssertionError(e);
+        }
     }
 
     /**
@@ -468,7 +473,12 @@
      *               adheres to RFC 2045.
      */
     public static String encodeToString(byte[] input, int offset, int len, int flags) {
-        return new String(encode(input, offset, len, flags));
+        try {
+            return new String(encode(input, offset, len, flags), "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            // US-ASCII is guaranteed to be available.
+            throw new AssertionError(e);
+        }
     }
 
     /**
@@ -497,13 +507,13 @@
      *               adheres to RFC 2045.
      */
     public static byte[] encode(byte[] input, int offset, int len, int flags) {
-        EncoderState state = new EncoderState(flags, null);
+        Encoder encoder = new Encoder(flags, null);
 
         // Compute the exact length of the array we will produce.
         int output_len = len / 3 * 4;
 
         // Account for the tail of the data and the padding bytes, if any.
-        if (state.do_padding) {
+        if (encoder.do_padding) {
             if (len % 3 > 0) {
                 output_len += 4;
             }
@@ -516,190 +526,215 @@
         }
 
         // Account for the newlines, if any.
-        if (state.do_newline && len > 0) {
-            output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (state.do_cr ? 2 : 1);
+        if (encoder.do_newline && len > 0) {
+            output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
+                (encoder.do_cr ? 2 : 1);
         }
 
-        state.output = new byte[output_len];
-        encodeInternal(input, offset, len, state, true);
+        encoder.output = new byte[output_len];
+        encoder.process(input, offset, len, true);
 
-        assert state.op == output_len;
+        assert encoder.op == output_len;
 
-        return state.output;
+        return encoder.output;
     }
 
-    /* package */ static class EncoderState {
-        public byte[] output;
-        public int op;
+    /* package */ static class Encoder extends Coder {
+        /**
+         * Emit a new line every this many output tuples.  Corresponds to
+         * a 76-character line length (the maximum allowable according to
+         * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
+         */
+        public static final int LINE_GROUPS = 19;
 
-        final public byte[] tail;
-        public int tailLen;
-        public int count;
+        /**
+         * Lookup table for turning Base64 alphabet positions (6 bits)
+         * into output bytes.
+         */
+        private static final byte ENCODE[] = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
+        };
+
+        /**
+         * Lookup table for turning Base64 alphabet positions (6 bits)
+         * into output bytes.
+         */
+        private static final byte ENCODE_WEBSAFE[] = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
+        };
+
+        final private byte[] tail;
+        /* package */ int tailLen;
+        private int count;
 
         final public boolean do_padding;
         final public boolean do_newline;
         final public boolean do_cr;
-        final public byte[] alphabet;
+        final private byte[] alphabet;
 
-        public EncoderState(int flags, byte[] output) {
+        public Encoder(int flags, byte[] output) {
             this.output = output;
 
             do_padding = (flags & NO_PADDING) == 0;
             do_newline = (flags & NO_WRAP) == 0;
             do_cr = (flags & CRLF) != 0;
-            alphabet = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+            alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
 
             tail = new byte[2];
             tailLen = 0;
 
             count = do_newline ? LINE_GROUPS : -1;
         }
-    }
 
-    /**
-     * Encode another block of input data.
-     *
-     * @param estate an EncoderState object whose (caller-provided)
-     *        output array is big enough to hold all the encoded data.
-     *        On return, estate.op will be set to the length of the
-     *        encoded data.
-     * @param finish true if this is the final call to encodeInternal
-     *        with the given EncoderState object.  Will finalize the
-     *        encoder state and include any final bytes in the output.
-     */
-    static void encodeInternal(byte[] input, int offset, int len,
-                               final EncoderState estate, boolean finish) {
-        final boolean do_cr = estate.do_cr;
-        final boolean do_newline = estate.do_newline;
-        final boolean do_padding = estate.do_padding;
-        final byte[] output = estate.output;
-
-        int op = 0;
-
-        int p = offset;
-        len += offset;
-        int v = -1;
-        int count = estate.count;
-
-        // First we need to concatenate the tail of the previous call
-        // with any input bytes available now and see if we can empty
-        // the tail.
-
-        switch (estate.tailLen) {
-            case 0:
-                // There was no tail.
-                break;
-
-            case 1:
-                if (p+2 <= len) {
-                    // A 1-byte tail with at least 2 bytes of
-                    // input available now.
-                    v = ((estate.tail[0] & 0xff) << 16) |
-                        ((input[p++] & 0xff) << 8) |
-                        (input[p++] & 0xff);
-                    estate.tailLen = 0;
-                };
-                break;
-
-            case 2:
-                if (p+1 <= len) {
-                    // A 2-byte tail with at least 1 byte of input.
-                    v = ((estate.tail[0] & 0xff) << 16) |
-                        ((estate.tail[1] & 0xff) << 8) |
-                        (input[p++] & 0xff);
-                    estate.tailLen = 0;
-                }
-                break;
+        /**
+         * @return an overestimate for the number of bytes {@code
+         * len} bytes could encode to.
+         */
+        public int maxOutputSize(int len) {
+            return len * 8/5 + 10;
         }
 
-        if (v != -1) {
-            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-            output[op++] = estate.alphabet[v & 0x3f];
-            if (--count == 0) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-                count = LINE_GROUPS;
+        public boolean process(byte[] input, int offset, int len, boolean finish) {
+            // Using local variables makes the encoder about 9% faster.
+            final byte[] alphabet = this.alphabet;
+            final byte[] output = this.output;
+            int op = 0;
+            int count = this.count;
+
+            int p = offset;
+            len += offset;
+            int v = -1;
+
+            // First we need to concatenate the tail of the previous call
+            // with any input bytes available now and see if we can empty
+            // the tail.
+
+            switch (tailLen) {
+                case 0:
+                    // There was no tail.
+                    break;
+
+                case 1:
+                    if (p+2 <= len) {
+                        // A 1-byte tail with at least 2 bytes of
+                        // input available now.
+                        v = ((tail[0] & 0xff) << 16) |
+                            ((input[p++] & 0xff) << 8) |
+                            (input[p++] & 0xff);
+                        tailLen = 0;
+                    };
+                    break;
+
+                case 2:
+                    if (p+1 <= len) {
+                        // A 2-byte tail with at least 1 byte of input.
+                        v = ((tail[0] & 0xff) << 16) |
+                            ((tail[1] & 0xff) << 8) |
+                            (input[p++] & 0xff);
+                        tailLen = 0;
+                    }
+                    break;
             }
-        }
 
-        // At this point either there is no tail, or there are fewer
-        // than 3 bytes of input available.
-
-        // The main loop, turning 3 input bytes into 4 output bytes on
-        // each iteration.
-        while (p+3 <= len) {
-            v = ((input[p++] & 0xff) << 16) |
-                ((input[p++] & 0xff) << 8) |
-                (input[p++] & 0xff);
-            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-            output[op++] = estate.alphabet[v & 0x3f];
-            if (--count == 0) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-                count = LINE_GROUPS;
-            }
-        }
-
-        if (finish) {
-            // Finish up the tail of the input.  Note that we need to
-            // consume any bytes in estate.tail before any bytes
-            // remaining in input; there should be at most two bytes
-            // total.
-
-            if (p-estate.tailLen == len-1) {
-                int t = 0;
-                v = ((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 4;
-                estate.tailLen -= t;
-                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-                output[op++] = estate.alphabet[v & 0x3f];
-                if (do_padding) {
-                    output[op++] = '=';
-                    output[op++] = '=';
+            if (v != -1) {
+                output[op++] = alphabet[(v >> 18) & 0x3f];
+                output[op++] = alphabet[(v >> 12) & 0x3f];
+                output[op++] = alphabet[(v >> 6) & 0x3f];
+                output[op++] = alphabet[v & 0x3f];
+                if (--count == 0) {
+                    if (do_cr) output[op++] = '\r';
+                    output[op++] = '\n';
+                    count = LINE_GROUPS;
                 }
-                if (do_newline) {
+            }
+
+            // At this point either there is no tail, or there are fewer
+            // than 3 bytes of input available.
+
+            // The main loop, turning 3 input bytes into 4 output bytes on
+            // each iteration.
+            while (p+3 <= len) {
+                v = ((input[p] & 0xff) << 16) |
+                    ((input[p+1] & 0xff) << 8) |
+                    (input[p+2] & 0xff);
+                output[op] = alphabet[(v >> 18) & 0x3f];
+                output[op+1] = alphabet[(v >> 12) & 0x3f];
+                output[op+2] = alphabet[(v >> 6) & 0x3f];
+                output[op+3] = alphabet[v & 0x3f];
+                p += 3;
+                op += 4;
+                if (--count == 0) {
+                    if (do_cr) output[op++] = '\r';
+                    output[op++] = '\n';
+                    count = LINE_GROUPS;
+                }
+            }
+
+            if (finish) {
+                // Finish up the tail of the input.  Note that we need to
+                // consume any bytes in tail before any bytes
+                // remaining in input; there should be at most two bytes
+                // total.
+
+                if (p-tailLen == len-1) {
+                    int t = 0;
+                    v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
+                    tailLen -= t;
+                    output[op++] = alphabet[(v >> 6) & 0x3f];
+                    output[op++] = alphabet[v & 0x3f];
+                    if (do_padding) {
+                        output[op++] = '=';
+                        output[op++] = '=';
+                    }
+                    if (do_newline) {
+                        if (do_cr) output[op++] = '\r';
+                        output[op++] = '\n';
+                    }
+                } else if (p-tailLen == len-2) {
+                    int t = 0;
+                    v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
+                        (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
+                    tailLen -= t;
+                    output[op++] = alphabet[(v >> 12) & 0x3f];
+                    output[op++] = alphabet[(v >> 6) & 0x3f];
+                    output[op++] = alphabet[v & 0x3f];
+                    if (do_padding) {
+                        output[op++] = '=';
+                    }
+                    if (do_newline) {
+                        if (do_cr) output[op++] = '\r';
+                        output[op++] = '\n';
+                    }
+                } else if (do_newline && op > 0 && count != LINE_GROUPS) {
                     if (do_cr) output[op++] = '\r';
                     output[op++] = '\n';
                 }
-            } else if (p-estate.tailLen == len-2) {
-                int t = 0;
-                v = (((estate.tailLen > 1 ? estate.tail[t++] : input[p++]) & 0xff) << 10) |
-                    (((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 2);
-                estate.tailLen -= t;
-                output[op++] = estate.alphabet[(v >> 12) & 0x3f];
-                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
-                output[op++] = estate.alphabet[v & 0x3f];
-                if (do_padding) {
-                    output[op++] = '=';
+
+                assert tailLen == 0;
+                assert p == len;
+            } else {
+                // Save the leftovers in tail to be consumed on the next
+                // call to encodeInternal.
+
+                if (p == len-1) {
+                    tail[tailLen++] = input[p];
+                } else if (p == len-2) {
+                    tail[tailLen++] = input[p];
+                    tail[tailLen++] = input[p+1];
                 }
-                if (do_newline) {
-                    if (do_cr) output[op++] = '\r';
-                    output[op++] = '\n';
-                }
-            } else if (do_newline && op > 0 && count != LINE_GROUPS) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
             }
 
-            assert estate.tailLen == 0;
-            assert p == len;
-        } else {
-            // Save the leftovers in tail to be consumed on the next
-            // call to encodeInternal.
+            this.op = op;
+            this.count = count;
 
-            if (p == len-1) {
-                estate.tail[estate.tailLen++] = input[p];
-            } else if (p == len-2) {
-                estate.tail[estate.tailLen++] = input[p];
-                estate.tail[estate.tailLen++] = input[p+1];
-            }
+            return true;
         }
-
-        estate.op = op;
-        estate.count = count;
     }
 
     private Base64() { }   // don't instantiate
diff --git a/core/java/android/util/base64/Base64InputStream.java b/core/java/android/util/base64/Base64InputStream.java
index 646bbdb..935939e 100644
--- a/core/java/android/util/base64/Base64InputStream.java
+++ b/core/java/android/util/base64/Base64InputStream.java
@@ -25,16 +25,13 @@
  * it.
  */
 public class Base64InputStream extends FilterInputStream {
-    private final boolean encode;
-    private final Base64.EncoderState estate;
-    private final Base64.DecoderState dstate;
+    private final Base64.Coder coder;
 
     private static byte[] EMPTY = new byte[0];
 
     private static final int BUFFER_SIZE = 2048;
     private boolean eof;
     private byte[] inputBuffer;
-    private byte[] outputBuffer;
     private int outputStart;
     private int outputEnd;
 
@@ -63,22 +60,14 @@
      */
     public Base64InputStream(InputStream in, int flags, boolean encode) {
         super(in);
-        this.encode = encode;
         eof = false;
         inputBuffer = new byte[BUFFER_SIZE];
         if (encode) {
-            // len*8/5+10 is an overestimate of the most bytes the
-            // encoder can produce for len bytes of input.
-            outputBuffer = new byte[BUFFER_SIZE * 8/5 + 10];
-            estate = new Base64.EncoderState(flags, outputBuffer);
-            dstate = null;
+            coder = new Base64.Encoder(flags, null);
         } else {
-            // len*3/4+10 is an overestimate of the most bytes the
-            // decoder can produce for len bytes of input.
-            outputBuffer = new byte[BUFFER_SIZE * 3/4 + 10];
-            estate = null;
-            dstate = new Base64.DecoderState(flags, outputBuffer);
+            coder = new Base64.Decoder(flags, null);
         }
+        coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)];
         outputStart = 0;
         outputEnd = 0;
     }
@@ -123,7 +112,7 @@
         if (outputStart >= outputEnd) {
             return -1;
         } else {
-            return outputBuffer[outputStart++];
+            return coder.output[outputStart++];
         }
     }
 
@@ -135,36 +124,30 @@
             return -1;
         }
         int bytes = Math.min(len, outputEnd-outputStart);
-        System.arraycopy(outputBuffer, outputStart, b, off, bytes);
+        System.arraycopy(coder.output, outputStart, b, off, bytes);
         outputStart += bytes;
         return bytes;
     }
 
     /**
      * Read data from the input stream into inputBuffer, then
-     * decode/encode it into the empty outputBuffer, and reset the
+     * decode/encode it into the empty coder.output, and reset the
      * outputStart and outputEnd pointers.
      */
     private void refill() throws IOException {
         if (eof) return;
         int bytesRead = in.read(inputBuffer);
-        if (encode) {
-            if (bytesRead == -1) {
-                eof = true;
-                Base64.encodeInternal(EMPTY, 0, 0, estate, true);
-            } else {
-                Base64.encodeInternal(inputBuffer, 0, bytesRead, estate, false);
-            }
-            outputEnd = estate.op;
+        boolean success;
+        if (bytesRead == -1) {
+            eof = true;
+            success = coder.process(EMPTY, 0, 0, true);
         } else {
-            if (bytesRead == -1) {
-                eof = true;
-                Base64.decodeInternal(EMPTY, 0, 0, dstate, true);
-            } else {
-                Base64.decodeInternal(inputBuffer, 0, bytesRead, dstate, false);
-            }
-            outputEnd = dstate.op;
+            success = coder.process(inputBuffer, 0, bytesRead, false);
         }
+        if (!success) {
+            throw new IOException("bad base-64");
+        }
+        outputEnd = coder.op;
         outputStart = 0;
     }
 }
diff --git a/core/java/android/util/base64/Base64OutputStream.java b/core/java/android/util/base64/Base64OutputStream.java
index 8edb511..35e9a2b 100644
--- a/core/java/android/util/base64/Base64OutputStream.java
+++ b/core/java/android/util/base64/Base64OutputStream.java
@@ -25,9 +25,7 @@
  * it, writing the resulting data to another OutputStream.
  */
 public class Base64OutputStream extends FilterOutputStream {
-    private final boolean encode;
-    private final Base64.EncoderState estate;
-    private final Base64.DecoderState dstate;
+    private final Base64.Coder coder;
     private final int flags;
 
     private byte[] buffer = null;
@@ -62,13 +60,10 @@
     public Base64OutputStream(OutputStream out, int flags, boolean encode) {
         super(out);
         this.flags = flags;
-        this.encode = encode;
         if (encode) {
-            estate = new Base64.EncoderState(flags, null);
-            dstate = null;
+            coder = new Base64.Encoder(flags, null);
         } else {
-            estate = null;
-            dstate = new Base64.DecoderState(flags, null);
+            coder = new Base64.Decoder(flags, null);
         }
     }
 
@@ -107,12 +102,28 @@
     }
 
     public void close() throws IOException {
-        flushBuffer();
-        internalWrite(EMPTY, 0, 0, true);
-        if ((flags & Base64.NO_CLOSE) == 0) {
-            out.close();
-        } else {
-            out.flush();
+        IOException thrown = null;
+        try {
+            flushBuffer();
+            internalWrite(EMPTY, 0, 0, true);
+        } catch (IOException e) {
+            thrown = e;
+        }
+
+        try {
+            if ((flags & Base64.NO_CLOSE) == 0) {
+                out.close();
+            } else {
+                out.flush();
+            }
+        } catch (IOException e) {
+            if (thrown != null) {
+                thrown = e;
+            }
+        }
+
+        if (thrown != null) {
+            throw thrown;
         }
     }
 
@@ -123,21 +134,11 @@
      *        encoder/decoder state to be finalized.
      */
     private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
-        if (encode) {
-            // len*8/5+10 is an overestimate of the most bytes the
-            // encoder can produce for len bytes of input.
-            estate.output = embiggen(estate.output, len*8/5+10);
-            Base64.encodeInternal(b, off, len, estate, finish);
-            out.write(estate.output, 0, estate.op);
-        } else {
-            // len*3/4+10 is an overestimate of the most bytes the
-            // decoder can produce for len bytes of input.
-            dstate.output = embiggen(dstate.output, len*3/4+10);
-            if (!Base64.decodeInternal(b, off, len, dstate, finish)) {
-                throw new IOException("bad base-64");
-            }
-            out.write(dstate.output, 0, dstate.op);
+        coder.output = embiggen(coder.output, coder.maxOutputSize(len));
+        if (!coder.process(b, off, len, finish)) {
+            throw new IOException("bad base-64");
         }
+        out.write(coder.output, 0, coder.op);
     }
 
     /**
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 3c79200..58f998e 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -465,10 +465,10 @@
         case MotionEvent.ACTION_POINTER_UP:
             // Ending a multitouch gesture and going back to 1 finger
             if (mIgnoreMultitouch && ev.getPointerCount() == 2) {
-                int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK)
-                        >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0;
-                mLastMotionX = ev.getX(id);
-                mLastMotionY = ev.getY(id);
+                int index = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
+                mLastMotionX = ev.getX(index);
+                mLastMotionY = ev.getY(index);
                 mVelocityTracker.recycle();
                 mVelocityTracker = VelocityTracker.obtain();
             }
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ca907af..d648e96 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -76,61 +76,81 @@
     public static final int ACTION_POINTER_DOWN     = 5;
     
     /**
-     * Synonym for {@link #ACTION_POINTER_DOWN} with
-     * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done.
-     */
-    public static final int ACTION_POINTER_1_DOWN   = ACTION_POINTER_DOWN | 0x0000;
-    
-    /**
-     * Synonym for {@link #ACTION_POINTER_DOWN} with
-     * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done.
-     */
-    public static final int ACTION_POINTER_2_DOWN   = ACTION_POINTER_DOWN | 0x0100;
-    
-    /**
-     * Synonym for {@link #ACTION_POINTER_DOWN} with
-     * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done.
-     */
-    public static final int ACTION_POINTER_3_DOWN   = ACTION_POINTER_DOWN | 0x0200;
-    
-    /**
      * A non-primary pointer has gone up.  The bits in
      * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
      */
     public static final int ACTION_POINTER_UP       = 6;
     
     /**
-     * Synonym for {@link #ACTION_POINTER_UP} with
-     * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up.
+     * Bits in the action code that represent a pointer index, used with
+     * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}.  Shifting
+     * down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer
+     * index where the data for the pointer going up or down can be found; you can
+     * get its identifier with {@link #getPointerId(int)} and the actual
+     * data with {@link #getX(int)} etc.
      */
+    public static final int ACTION_POINTER_INDEX_MASK  = 0xff00;
+    
+    /**
+     * Bit shift for the action bits holding the pointer index as
+     * defined by {@link #ACTION_POINTER_INDEX_MASK}.
+     */
+    public static final int ACTION_POINTER_INDEX_SHIFT = 8;
+    
+    /**
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_DOWN}.
+     */
+    @Deprecated
+    public static final int ACTION_POINTER_1_DOWN   = ACTION_POINTER_DOWN | 0x0000;
+    
+    /**
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_DOWN}.
+     */
+    @Deprecated
+    public static final int ACTION_POINTER_2_DOWN   = ACTION_POINTER_DOWN | 0x0100;
+    
+    /**
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_DOWN}.
+     */
+    @Deprecated
+    public static final int ACTION_POINTER_3_DOWN   = ACTION_POINTER_DOWN | 0x0200;
+    
+    /**
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_UP}.
+     */
+    @Deprecated
     public static final int ACTION_POINTER_1_UP     = ACTION_POINTER_UP | 0x0000;
     
     /**
-     * Synonym for {@link #ACTION_POINTER_UP} with
-     * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up.
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_UP}.
      */
+    @Deprecated
     public static final int ACTION_POINTER_2_UP     = ACTION_POINTER_UP | 0x0100;
     
     /**
-     * Synonym for {@link #ACTION_POINTER_UP} with
-     * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up.
+     * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+     * data index associated with {@link #ACTION_POINTER_UP}.
      */
+    @Deprecated
     public static final int ACTION_POINTER_3_UP     = ACTION_POINTER_UP | 0x0200;
     
     /**
-     * Bits in the action code that represent a pointer ID, used with
-     * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}.  Pointer IDs
-     * start at 0, with 0 being the primary (first) pointer in the motion.  Note
-     * that this not <em>not</em> an index into the array of pointer values,
-     * which is compacted to only contain pointers that are down; the pointer
-     * ID for a particular index can be found with {@link #findPointerIndex}.
+     * @deprecated Renamed to {@link #ACTION_POINTER_INDEX_MASK} to match
+     * the actual data contained in these bits.
      */
+    @Deprecated
     public static final int ACTION_POINTER_ID_MASK  = 0xff00;
     
     /**
-     * Bit shift for the action bits holding the pointer identifier as
-     * defined by {@link #ACTION_POINTER_ID_MASK}.
+     * @deprecated Renamed to {@link #ACTION_POINTER_INDEX_SHIFT} to match
+     * the actual data contained in these bits.
      */
+    @Deprecated
     public static final int ACTION_POINTER_ID_SHIFT = 8;
     
     private static final boolean TRACK_RECYCLED_LOCATION = false;
@@ -618,13 +638,39 @@
     /**
      * Return the kind of action being performed -- one of either
      * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
-     * {@link #ACTION_CANCEL}.
+     * {@link #ACTION_CANCEL}.  Consider using {@link #getActionMasked}
+     * and {@link #getActionIndex} to retrieve the separate masked action
+     * and pointer index.
      */
     public final int getAction() {
         return mAction;
     }
 
     /**
+     * Return the masked action being performed, without pointer index
+     * information.  May be any of the actions: {@link #ACTION_DOWN},
+     * {@link #ACTION_MOVE}, {@link #ACTION_UP}, {@link #ACTION_CANCEL},
+     * {@link #ACTION_POINTER_DOWN}, or {@link #ACTION_POINTER_UP}.
+     * Use {@link #getActionIndex} to return the index associated with
+     * pointer actions.
+     */
+    public final int getActionMasked() {
+        return mAction & ACTION_MASK;
+    }
+
+    /**
+     * For {@link #ACTION_POINTER_DOWN} or {@link #ACTION_POINTER_UP}
+     * as returned by {@link #getActionMasked}, this returns the associated
+     * pointer index.  The index may be used with {@link #getPointerId(int)},
+     * {@link #getX(int)}, {@link #getY(int)}, {@link #getPressure(int)},
+     * and {@link #getSize(int)} to get information about the pointer that has
+     * gone down or up.
+     */
+    public final int getActionIndex() {
+        return (mAction & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
+    }
+
+    /**
      * Returns the time (in ms) when the user originally pressed down to start
      * a stream of position events.
      */
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 9a8ee02..91fd6f1 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -124,24 +124,37 @@
      * @param ev The MotionEvent you received and would like to track.
      */
     public void addMovement(MotionEvent ev) {
-        long time = ev.getEventTime();
         final int N = ev.getHistorySize();
         final int pointerCount = ev.getPointerCount();
-        for (int p = 0; p < pointerCount; p++) {
-            for (int i=0; i<N; i++) {
-                addPoint(p, ev.getHistoricalX(p, i), ev.getHistoricalY(p, i),
-                        ev.getHistoricalEventTime(i));
+        int touchIndex = (mLastTouch + 1) % NUM_PAST;
+        for (int i=0; i<N; i++) {
+            for (int id = 0; id < MotionEvent.BASE_AVAIL_POINTERS; id++) {
+                mPastTime[id][touchIndex] = 0;
             }
-            addPoint(p, ev.getX(p), ev.getY(p), time);
-        }
-    }
+            for (int p = 0; p < pointerCount; p++) {
+                int id = ev.getPointerId(p);
+                mPastX[id][touchIndex] = ev.getHistoricalX(p, i);
+                mPastY[id][touchIndex] = ev.getHistoricalY(p, i);
+                mPastTime[id][touchIndex] = ev.getHistoricalEventTime(i);
+            }
 
-    private void addPoint(int pos, float x, float y, long time) {
-        final int lastTouch = (mLastTouch + 1) % NUM_PAST;
-        mPastX[pos][lastTouch] = x;
-        mPastY[pos][lastTouch] = y;
-        mPastTime[pos][lastTouch] = time;
-        mLastTouch = lastTouch;
+            touchIndex = (touchIndex + 1) % NUM_PAST;
+        }
+
+        // During calculation any pointer values with a time of 0 are treated
+        // as a break in input. Initialize all to 0 for each new touch index.
+        for (int id = 0; id < MotionEvent.BASE_AVAIL_POINTERS; id++) {
+            mPastTime[id][touchIndex] = 0;
+        }
+        final long time = ev.getEventTime();
+        for (int p = 0; p < pointerCount; p++) {
+            int id = ev.getPointerId(p);
+            mPastX[id][touchIndex] = ev.getX(p);
+            mPastY[id][touchIndex] = ev.getY(p);
+            mPastTime[id][touchIndex] = time;
+        }
+
+        mLastTouch = touchIndex;
     }
 
     /**
@@ -177,10 +190,12 @@
             // find oldest acceptable time
             int oldestTouch = lastTouch;
             if (pastTime[lastTouch] > 0) { // cleared ?
-                oldestTouch = (lastTouch + 1) % NUM_PAST;
                 final float acceptableTime = pastTime[lastTouch] - LONGEST_PAST_TIME;
-                while (pastTime[oldestTouch] < acceptableTime) {
-                    oldestTouch = (oldestTouch + 1) % NUM_PAST;
+                int nextOldestTouch = (NUM_PAST + oldestTouch - 1) % NUM_PAST;
+                while (pastTime[nextOldestTouch] >= acceptableTime &&
+                        nextOldestTouch != lastTouch) {
+                    oldestTouch = nextOldestTouch;
+                    nextOldestTouch = (NUM_PAST + oldestTouch - 1) % NUM_PAST;
                 }
             }
         
@@ -241,25 +256,25 @@
      * Retrieve the last computed X velocity.  You must first call
      * {@link #computeCurrentVelocity(int)} before calling this function.
      * 
-     * @param pos Which pointer's velocity to return.
+     * @param id Which pointer's velocity to return.
      * @return The previously computed X velocity.
      * 
      * @hide Pending API approval
      */
-    public float getXVelocity(int pos) {
-        return mXVelocity[pos];
+    public float getXVelocity(int id) {
+        return mXVelocity[id];
     }
     
     /**
      * Retrieve the last computed Y velocity.  You must first call
      * {@link #computeCurrentVelocity(int)} before calling this function.
      * 
-     * @param pos Which pointer's velocity to return.
+     * @param id Which pointer's velocity to return.
      * @return The previously computed Y velocity.
      * 
      * @hide Pending API approval
      */
-    public float getYVelocity(int pos) {
-        return mYVelocity[pos];
+    public float getYVelocity(int id) {
+        return mYVelocity[id];
     }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9148a18..ae6c666 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -5893,6 +5893,10 @@
                     }
                     break;
                 case UPDATE_TEXT_SELECTION_MSG_ID:
+                    // If no textfield was in focus, and the user touched one,
+                    // causing it to send this message, then WebTextView has not
+                    // been set up yet.  Rebuild it so it can set its selection.
+                    rebuildWebTextView();
                     if (inEditingMode()
                             && mWebTextView.isSameTextField(msg.arg1)
                             && msg.arg2 == mTextGeneration) {
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 30a38df..b9acf5e 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1856,8 +1856,11 @@
             final int top = view.getTop();
             int height = view.getHeight();
             if (height > 0) {
-                final int whichRow = mFirstPosition / mNumColumns;
-                return Math.max(whichRow * 100 - (top * 100) / height, 0);
+                final int numColumns = mNumColumns;
+                final int whichRow = mFirstPosition / numColumns;
+                final int rowCount = (mItemCount + numColumns - 1) / numColumns;
+                return Math.max(whichRow * 100 - (top * 100) / height +
+                        (int) ((float) mScrollY / getHeight() * rowCount * 100), 0);
             }
         }
         return 0;
@@ -1868,7 +1871,12 @@
         // TODO: Account for vertical spacing too
         final int numColumns = mNumColumns;
         final int rowCount = (mItemCount + numColumns - 1) / numColumns;
-        return Math.max(rowCount * 100, 0);
+        int result = Math.max(rowCount * 100, 0);
+        if (mScrollY != 0) {
+            // Compensate for overscroll
+            result += Math.abs((int) ((float) mScrollY / getHeight() * rowCount * 100));
+        }
+        return result;
     }
 }
 
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index c62724c..a7b819a 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -890,14 +890,15 @@
      */
     @Override
     protected int computeHorizontalScrollRange() {
-        int count = getChildCount();
+        final int count = getChildCount();
+        final int contentWidth = getWidth() - mPaddingLeft - mPaddingRight;
         if (count == 0) {
-            return getWidth();
+            return contentWidth;
         }
         
         int scrollRange = getChildAt(0).getRight();
-        int scrollX = mScrollX;
-        int overscrollRight = scrollRange - getWidth() - mPaddingLeft - mPaddingRight;
+        final int scrollX = mScrollX;
+        final int overscrollRight = Math.max(0, scrollRange - contentWidth);
         if (scrollX < 0) {
             scrollRange -= scrollX;
         } else if (scrollX > overscrollRight) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 2ee7ad5..52ed11d 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -892,14 +892,15 @@
      */
     @Override
     protected int computeVerticalScrollRange() {
-        int count = getChildCount();
+        final int count = getChildCount();
+        final int contentHeight = getHeight() - mPaddingBottom - mPaddingTop;
         if (count == 0) {
-            return getHeight();
+            return contentHeight;
         }
         
         int scrollRange = getChildAt(0).getBottom();
-        int scrollY = mScrollY;
-        int overscrollBottom = scrollRange - getHeight() - mPaddingBottom - mPaddingTop;
+        final int scrollY = mScrollY;
+        final int overscrollBottom = Math.max(0, scrollRange - contentHeight);
         if (scrollY < 0) {
             scrollRange -= scrollY;
         } else if (scrollY > overscrollBottom) {
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 726e28f..c0e9587 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -25,4 +25,5 @@
                 String key, String resFileName);
     boolean copyResource(in Uri packageURI,
                 in ParcelFileDescriptor outStream);
+    int getRecommendedInstallLocation(in Uri fileUri);
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
new file mode 100644
index 0000000..c5b869b
--- /dev/null
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -0,0 +1,182 @@
+/*
+ * 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.internal.content;
+
+import android.os.storage.IMountService;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.storage.StorageResultCode;
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ * Constants used internally between the PackageManager
+ * and media container service transports.
+ * Some utility methods to invoke MountService api.
+ */
+public class PackageHelper {
+    public static final int RECOMMEND_INSTALL_INTERNAL = 1;
+    public static final int RECOMMEND_INSTALL_EXTERNAL = 2;
+    public static final int RECOMMEND_FAILED_INSUFFICIENT_STORAGE = -1;
+    public static final int RECOMMEND_FAILED_INVALID_APK = -2;
+    private static final boolean DEBUG_SD_INSTALL = true;
+    private static final String TAG = "PackageHelper";
+
+    public static IMountService getMountService() {
+        IBinder service = ServiceManager.getService("mount");
+        if (service != null) {
+            return IMountService.Stub.asInterface(service);
+        } else {
+            Log.e(TAG, "Can't get mount service");
+        }
+        return null;
+    }
+
+    public static String createSdDir(File tmpPackageFile, String cid,
+            String sdEncKey, int uid) {
+        // Create mount point via MountService
+        IMountService mountService = getMountService();
+        long len = tmpPackageFile.length();
+        int mbLen = (int) (len/(1024*1024));
+        if ((len - (mbLen * 1024 * 1024)) > 0) {
+            mbLen++;
+        }
+        if (DEBUG_SD_INSTALL) Log.i(TAG, "Size of resource " + mbLen);
+
+        try {
+            int rc = mountService.createSecureContainer(
+                    cid, mbLen, "vfat", sdEncKey, uid);
+            if (rc != StorageResultCode.OperationSucceeded) {
+                Log.e(TAG, "Failed to create secure container " + cid);
+                return null;
+            }
+            String cachePath = mountService.getSecureContainerPath(cid);
+            if (DEBUG_SD_INSTALL) Log.i(TAG, "Created secure container " + cid +
+                    " at " + cachePath);
+                return cachePath;
+        } catch (RemoteException e) {
+            Log.e(TAG, "MountService running?");
+        }
+        return null;
+    }
+
+   public static String mountSdDir(String cid, String key, int ownerUid) {
+    try {
+        int rc = getMountService().mountSecureContainer(cid, key, ownerUid);
+        if (rc != StorageResultCode.OperationSucceeded) {
+            Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
+            return null;
+        }
+        return getMountService().getSecureContainerPath(cid);
+    } catch (RemoteException e) {
+        Log.e(TAG, "MountService running?");
+    }
+    return null;
+   }
+
+   public static boolean unMountSdDir(String cid) {
+    try {
+        int rc = getMountService().unmountSecureContainer(cid);
+        if (rc != StorageResultCode.OperationSucceeded) {
+            Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
+            return false;
+        }
+        return true;
+    } catch (RemoteException e) {
+        Log.e(TAG, "MountService running?");
+    }
+        return false;
+   }
+
+   public static boolean renameSdDir(String oldId, String newId) {
+       try {
+           int rc = getMountService().renameSecureContainer(oldId, newId);
+           if (rc != StorageResultCode.OperationSucceeded) {
+               Log.e(TAG, "Failed to rename " + oldId + " to " +
+                       newId + "with rc " + rc);
+               return false;
+           }
+           return true;
+       } catch (RemoteException e) {
+           Log.i(TAG, "Failed ot rename  " + oldId + " to " + newId +
+                   " with exception : " + e);
+       }
+       return false;
+   }
+
+   public static String getSdDir(String cid) {
+       try {
+            return getMountService().getSecureContainerPath(cid);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get container path for " + cid +
+                " with exception " + e);
+        }
+        return null;
+   }
+
+    public static boolean finalizeSdDir(String cid) {
+        try {
+            int rc = getMountService().finalizeSecureContainer(cid);
+            if (rc != StorageResultCode.OperationSucceeded) {
+                Log.i(TAG, "Failed to finalize container " + cid);
+                return false;
+            }
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to finalize container " + cid +
+                    " with exception " + e);
+        }
+        return false;
+    }
+
+    public static boolean destroySdDir(String cid) {
+        try {
+            int rc = getMountService().destroySecureContainer(cid);
+            if (rc != StorageResultCode.OperationSucceeded) {
+                Log.i(TAG, "Failed to destroy container " + cid);
+                return false;
+            }
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to destroy container " + cid +
+                    " with exception " + e);
+        }
+        return false;
+    }
+
+    public static String[] getSecureContainerList() {
+        try {
+            return getMountService().getSecureContainerList();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get secure container list with exception" +
+                    e);
+        }
+        return null;
+    }
+
+   public static boolean isContainerMounted(String cid) {
+       try {
+           return getMountService().isSecureContainerMounted(cid);
+       } catch (RemoteException e) {
+           Log.e(TAG, "Failed to find out if container " + cid + " mounted");
+       }
+       return false;
+   }
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 57a28e6..c134d88 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -22,7 +22,6 @@
 import android.os.Build;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.ICheckinService;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/core/java/com/google/android/net/ParentalControl.java b/core/java/com/google/android/net/ParentalControl.java
deleted file mode 100644
index 71a3958..0000000
--- a/core/java/com/google/android/net/ParentalControl.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2008 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.google.android.net;
-
-import android.os.ICheckinService;
-import android.os.IParentalControlCallback;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-public class ParentalControl {
-    /**
-     * Strings to identify your app. To enable parental control checking for
-     * new apps, please add it here, and configure GServices accordingly.
-     */
-    public static final String VENDING = "vending";
-    public static final String YOUTUBE = "youtube";
-
-    /**
-     * This interface is supplied to getParentalControlState and is callback upon with
-     * the state of parental control.
-     */
-    public interface Callback {
-        /**
-         * This method will be called when the state of parental control is known. If state is
-         * null, then the state of parental control is unknown.
-         * @param state The state of parental control.
-         */
-        void onResult(ParentalControlState state);
-    }
-
-    private static class RemoteCallback extends IParentalControlCallback.Stub {
-        private Callback mCallback;
-
-        public RemoteCallback(Callback callback) {
-            mCallback = callback;
-        }
-
-        public void onResult(ParentalControlState state) {
-            if (mCallback != null) {
-                mCallback.onResult(state);
-            }
-        }
-    };
-
-    public static void getParentalControlState(Callback callback,
-                                               String requestingApp) {
-        ICheckinService service =
-          ICheckinService.Stub.asInterface(ServiceManager.getService("checkin"));
-
-        RemoteCallback remoteCallback = new RemoteCallback(callback);
-        try {
-            service.getParentalControlState(remoteCallback, requestingApp);
-        } catch (RemoteException e) {
-            // This should never happen.
-            Log.e("ParentalControl", "Failed to talk to the checkin service.");
-        }
-    }
-}
diff --git a/core/java/com/google/android/net/ParentalControlState.aidl b/core/java/com/google/android/net/ParentalControlState.aidl
deleted file mode 100644
index ed1326a..0000000
--- a/core/java/com/google/android/net/ParentalControlState.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright (c) 2008, 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.google.android.net;
-parcelable ParentalControlState;
diff --git a/core/java/com/google/android/net/ParentalControlState.java b/core/java/com/google/android/net/ParentalControlState.java
deleted file mode 100644
index 162a1f6..0000000
--- a/core/java/com/google/android/net/ParentalControlState.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2008 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.google.android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class ParentalControlState implements Parcelable {
-    public boolean isEnabled;
-    public String redirectUrl;
-
-    /**
-     * Used to read a ParentalControlStatus from a Parcel.
-     */
-    public static final Parcelable.Creator<ParentalControlState> CREATOR =
-        new Parcelable.Creator<ParentalControlState>() {
-              public ParentalControlState createFromParcel(Parcel source) {
-                    ParentalControlState status = new ParentalControlState();
-                    status.isEnabled = (source.readInt() == 1);
-                    status.redirectUrl = source.readString();
-                    return status;
-              }
-
-              public ParentalControlState[] newArray(int size) {
-                  return new ParentalControlState[size];
-              }
-        };
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel dest, int flags) {
-      dest.writeInt(isEnabled ? 1 : 0);
-      dest.writeString(redirectUrl);
-    }
-
-    @Override
-    public String toString() {
-        return isEnabled + ", " + redirectUrl;
-    }
-};
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 05d7b73..1353478 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -23,7 +23,8 @@
 #include "utils/Log.h"
 #include "unicode/uchar.h"
 
-#define DIRECTIONALITY_UNDEFINED (-1)
+#define PROPERTY_UNDEFINED (-1)
+
 // ICU => JDK mapping
 static int directionality_map[U_CHAR_DIRECTION_COUNT] = {
     0, // U_LEFT_TO_RIGHT (0) => DIRECTIONALITY_LEFT_TO_RIGHT (0)
@@ -79,7 +80,7 @@
                                  (src[i + 1] & 0x3FF);
             int dir = u_charDirection(c);
             if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT)
-                dir = DIRECTIONALITY_UNDEFINED;
+                dir = PROPERTY_UNDEFINED;
             else
                 dir = directionality_map[dir];
 
@@ -89,7 +90,7 @@
             int c = src[i];
             int dir = u_charDirection(c);
             if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT)
-                dest[i] = DIRECTIONALITY_UNDEFINED;
+                dest[i] = PROPERTY_UNDEFINED;
             else
                 dest[i] = directionality_map[dir];
         }
@@ -100,6 +101,60 @@
     env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT);
 }
 
+static jint getEastAsianWidth(JNIEnv* env, jobject obj, jchar input)
+{
+    int width = u_getIntPropertyValue(input, UCHAR_EAST_ASIAN_WIDTH);
+    if (width < 0 || width >= U_EA_COUNT)
+        width = PROPERTY_UNDEFINED;
+
+    return width;
+}
+
+static void getEastAsianWidths(JNIEnv* env, jobject obj, jcharArray srcArray,
+                               int start, int count, jbyteArray destArray)
+{
+    jchar* src = env->GetCharArrayElements(srcArray, NULL);
+    jbyte* dest = env->GetByteArrayElements(destArray, NULL);
+    if (src == NULL || dest == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        goto EA_END;
+    }
+
+    if (start < 0 || start > start + count
+            || env->GetArrayLength(srcArray) < (start + count)
+            || env->GetArrayLength(destArray) < count) {
+        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
+        goto EA_END;
+    }
+
+    for (int i = 0; i < count; i++) {
+        const int srci = start + i;
+        if (src[srci] >= 0xD800 && src[srci] <= 0xDBFF &&
+            i + 1 < count &&
+            src[srci + 1] >= 0xDC00 && src[srci + 1] <= 0xDFFF) {
+            int c = 0x00010000 + ((src[srci] - 0xD800) << 10) +
+                                 (src[srci + 1] & 0x3FF);
+            int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
+            if (width < 0 || width >= U_EA_COUNT)
+                width = PROPERTY_UNDEFINED;
+
+            dest[i++] = width;
+            dest[i] = width;
+        } else {
+            int c = src[srci];
+            int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
+            if (width < 0 || width >= U_EA_COUNT)
+                width = PROPERTY_UNDEFINED;
+
+            dest[i] = width;
+        }
+    }
+
+EA_END:
+    env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT);
+    env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT);
+}
+
 static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start, int count)
 {
     jchar* data = env->GetCharArrayElements(charArray, NULL);
@@ -140,6 +195,10 @@
 static JNINativeMethod gMethods[] = {
 	{ "getDirectionalities", "([C[BI)V",
         (void*) getDirectionalities },
+	{ "getEastAsianWidth", "(C)I",
+        (void*) getEastAsianWidth },
+	{ "getEastAsianWidths", "([CII[B)V",
+        (void*) getEastAsianWidths },
 	{ "mirror", "([CII)Z",
         (void*) mirror },
 	{ "getMirror", "(C)C",
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index d89a7e6..c152aa8 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -584,9 +584,9 @@
             inUtc = true;
 
 	    if (offset != 0) {
-	        if (len < tz_index + 5) {
+	        if (len < tz_index + 6) {
 	            char msg[100];
-	            sprintf(msg, "Unexpected length; should be %d characters", tz_index + 5);
+	            sprintf(msg, "Unexpected length; should be %d characters", tz_index + 6);
 	            jniThrowException(env, "android/util/TimeFormatException", msg);
 	            return false;
 	        }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8273dbf..a27d28f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1227,6 +1227,13 @@
         android:description="@string/permlab_copyProtectedData"
         android:protectionLevel="signature" />
 
+    <!-- Push messaging permission. 
+         @hide Used internally.
+     -->
+    <permission android:name="android.intent.category.MASTER_CLEAR.permission.PUSH_MESSAGE"
+          android:protectionLevel="signature" />
+    <uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.PUSH_MESSAGE"/>
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -1309,7 +1316,7 @@
                 <action android:name="android.intent.action.MASTER_CLEAR" />
 
                 <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
-                <action android:name="android.intent.action.REMOTE_INTENT" />
+                <action android:name="com.google.android.pushmessaging.intent.RECEIVE" />
                 <category android:name="android.intent.category.MASTER_CLEAR" />
             </intent-filter>
         </receiver>
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index 21ed4c5..fc7e787 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -141,7 +141,6 @@
      * Tests that startSearch() can be called multiple times without stopSearch()
      * in between.
      */
-    @MediumTest
     public void testStartSearchIdempotent() throws Exception {
          SearchManager searchManager = (SearchManager)
                  mContext.getSystemService(Context.SEARCH_SERVICE);
@@ -156,7 +155,6 @@
      * Tests that stopSearch() can be called when the search UI is not visible and can be
      * called multiple times without startSearch() in between.
      */
-    @MediumTest
     public void testStopSearchIdempotent() throws Exception {
          SearchManager searchManager = (SearchManager)
                  mContext.getSystemService(Context.SEARCH_SERVICE);
@@ -172,7 +170,6 @@
      * The goal of this test is to confirm that we can start and then
      * stop a simple search.
      */
-    @MediumTest
     public void testSearchManagerInvocations() throws Exception {
         SearchManager searchManager = (SearchManager)
                 mContext.getSystemService(Context.SEARCH_SERVICE);
diff --git a/core/tests/coretests/src/android/util/base64/Base64Test.java b/core/tests/coretests/src/android/util/base64/Base64Test.java
index 8f98b08..48192bb 100644
--- a/core/tests/coretests/src/android/util/base64/Base64Test.java
+++ b/core/tests/coretests/src/android/util/base64/Base64Test.java
@@ -134,25 +134,25 @@
     }
 
     public void testWebSafe() throws Exception {
-        assertEquals(BYTES, 0, Base64.decode("", Base64.WEB_SAFE));
-        assertEquals(BYTES, 1, Base64.decode("_w==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.WEB_SAFE));
-        assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.WEB_SAFE));
-        assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.WEB_SAFE));
-        assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.WEB_SAFE));
-        assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.WEB_SAFE));
-        assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.WEB_SAFE));
+        assertEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE));
+        assertEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE));
+        assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE));
+        assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE));
+        assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE));
+        assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE));
+        assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE));
+        assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE));
+        assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE));
 
-        assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.WEB_SAFE));
-        assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.WEB_SAFE));
-        assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.WEB_SAFE));
-        assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.WEB_SAFE));
-        assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.WEB_SAFE));
-        assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.WEB_SAFE));
-        assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.WEB_SAFE));
+        assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.URL_SAFE));
+        assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.URL_SAFE));
+        assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.URL_SAFE));
+        assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.URL_SAFE));
+        assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.URL_SAFE));
+        assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.URL_SAFE));
+        assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.URL_SAFE));
+        assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.URL_SAFE));
+        assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.URL_SAFE));
     }
 
     public void testFlags() throws Exception {
@@ -227,55 +227,55 @@
     }
 
     /**
-     * Tests that Base64.encodeInternal does correct handling of the
+     * Tests that Base64.Encoder.encode() does correct handling of the
      * tail for each call.
      *
      * This test is disabled because while it passes if you can get it
      * to run, android's test infrastructure currently doesn't allow
-     * us to get at package-private members (Base64.EncoderState in
+     * us to get at package-private members (Base64.Encoder in
      * this case).
      */
     public void XXXtestEncodeInternal() throws Exception {
         byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
         byte[] output = new byte[100];
 
-        Base64.EncoderState state = new Base64.EncoderState(Base64.NO_PADDING | Base64.NO_WRAP,
-                                                            output);
+        Base64.Encoder encoder = new Base64.Encoder(Base64.NO_PADDING | Base64.NO_WRAP,
+                                                    output);
 
-        Base64.encodeInternal(input, 0, 3, state, false);
-        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
+        encoder.process(input, 0, 3, false);
+        assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
+        assertEquals(0, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 3, state, false);
-        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
+        encoder.process(input, 0, 3, false);
+        assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
+        assertEquals(0, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals(0, state.op);
-        assertEquals(1, state.tailLen);
+        encoder.process(input, 0, 1, false);
+        assertEquals(0, encoder.op);
+        assertEquals(1, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals(0, state.op);
-        assertEquals(2, state.tailLen);
+        encoder.process(input, 0, 1, false);
+        assertEquals(0, encoder.op);
+        assertEquals(2, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 1, state, false);
-        assertEquals("YWFh".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
+        encoder.process(input, 0, 1, false);
+        assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op);
+        assertEquals(0, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals(0, state.op);
-        assertEquals(2, state.tailLen);
+        encoder.process(input, 0, 2, false);
+        assertEquals(0, encoder.op);
+        assertEquals(2, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals("YWJh".getBytes(), 4, state.output, state.op);
-        assertEquals(1, state.tailLen);
+        encoder.process(input, 0, 2, false);
+        assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op);
+        assertEquals(1, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 2, state, false);
-        assertEquals("YmFi".getBytes(), 4, state.output, state.op);
-        assertEquals(0, state.tailLen);
+        encoder.process(input, 0, 2, false);
+        assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op);
+        assertEquals(0, encoder.tailLen);
 
-        Base64.encodeInternal(input, 0, 1, state, true);
-        assertEquals("YQ".getBytes(), 2, state.output, state.op);
+        encoder.process(input, 0, 1, true);
+        assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op);
     }
 
     private static final String lipsum =
@@ -307,7 +307,7 @@
                           Base64.NO_WRAP,
                           Base64.NO_PADDING | Base64.NO_WRAP,
                           Base64.CRLF,
-                          Base64.WEB_SAFE };
+                          Base64.URL_SAFE };
         int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
         Random rng = new Random(32176L);
 
@@ -414,7 +414,7 @@
                           Base64.NO_WRAP,
                           Base64.NO_PADDING | Base64.NO_WRAP,
                           Base64.CRLF,
-                          Base64.WEB_SAFE };
+                          Base64.URL_SAFE };
         int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
         Random rng = new Random(32176L);
 
diff --git a/core/tests/coretests/src/com/google/android/net/ParentalControlTest.java b/core/tests/coretests/src/com/google/android/net/ParentalControlTest.java
deleted file mode 100644
index d8ffeab..0000000
--- a/core/tests/coretests/src/com/google/android/net/ParentalControlTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 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.google.android.net;
-
-import com.google.android.net.ParentalControl;
-import com.google.android.net.ParentalControlState;
-
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-public class ParentalControlTest extends AndroidTestCase {
-
-    private boolean mOnResultCalled = false;
-
-    public class Callback implements ParentalControl.Callback {
-        public void onResult(ParentalControlState state) {
-            synchronized (ParentalControlTest.class) {
-                mOnResultCalled = true;
-                ParentalControlTest.class.notifyAll();
-            }
-        }
-    }
-
-    @SmallTest
-    public void testParentalControlCallback() {
-        synchronized (ParentalControlTest.class) {
-            ParentalControl.getParentalControlState(new Callback(), null);
-            try {
-                long start = SystemClock.uptimeMillis();
-                ParentalControlTest.class.wait(20 * 1000);
-                long end = SystemClock.uptimeMillis();
-                Log.d("AndroidTests", "ParentalControlTest callback took " + (end-start) + " ms.");
-            } catch (InterruptedException ex) {
-            }
-        }
-
-        Assert.assertTrue(mOnResultCalled);
-    }
-}
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index 5dacc70..d7f7c7e 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -67,6 +67,11 @@
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
 	$(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \
 	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
diff --git a/data/sounds/AudioPackage3.mk b/data/sounds/AudioPackage3.mk
index f2f6212..64d6717 100644
--- a/data/sounds/AudioPackage3.mk
+++ b/data/sounds/AudioPackage3.mk
@@ -59,6 +59,11 @@
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
 	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
 	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
@@ -89,4 +94,3 @@
 	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
 	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
 	$(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg
-
diff --git a/data/sounds/AudioPackage4.mk b/data/sounds/AudioPackage4.mk
index 6c36bad..b011b78 100644
--- a/data/sounds/AudioPackage4.mk
+++ b/data/sounds/AudioPackage4.mk
@@ -46,6 +46,11 @@
 	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
diff --git a/data/sounds/effects/Dock.aif b/data/sounds/effects/Dock.aif
new file mode 100644
index 0000000..9f408cc
--- /dev/null
+++ b/data/sounds/effects/Dock.aif
Binary files differ
diff --git a/data/sounds/effects/Dock.ogg b/data/sounds/effects/Dock.ogg
new file mode 100644
index 0000000..1462813d
--- /dev/null
+++ b/data/sounds/effects/Dock.ogg
Binary files differ
diff --git a/data/sounds/effects/Lock.aiff b/data/sounds/effects/Lock.aiff
new file mode 100644
index 0000000..90870f2
--- /dev/null
+++ b/data/sounds/effects/Lock.aiff
Binary files differ
diff --git a/data/sounds/effects/Lock.ogg b/data/sounds/effects/Lock.ogg
new file mode 100644
index 0000000..841ee2e
--- /dev/null
+++ b/data/sounds/effects/Lock.ogg
Binary files differ
diff --git a/data/sounds/effects/LowBattery.aif b/data/sounds/effects/LowBattery.aif
new file mode 100644
index 0000000..9216583
--- /dev/null
+++ b/data/sounds/effects/LowBattery.aif
Binary files differ
diff --git a/data/sounds/effects/LowBattery.ogg b/data/sounds/effects/LowBattery.ogg
new file mode 100644
index 0000000..68eb2c3
--- /dev/null
+++ b/data/sounds/effects/LowBattery.ogg
Binary files differ
diff --git a/data/sounds/effects/Undock.aif b/data/sounds/effects/Undock.aif
new file mode 100644
index 0000000..fe9d0b05
--- /dev/null
+++ b/data/sounds/effects/Undock.aif
Binary files differ
diff --git a/data/sounds/effects/Undock.ogg b/data/sounds/effects/Undock.ogg
new file mode 100644
index 0000000..0053066
--- /dev/null
+++ b/data/sounds/effects/Undock.ogg
Binary files differ
diff --git a/data/sounds/effects/Unlock.aiff b/data/sounds/effects/Unlock.aiff
new file mode 100644
index 0000000..546ea39
--- /dev/null
+++ b/data/sounds/effects/Unlock.aiff
Binary files differ
diff --git a/data/sounds/effects/Unlock.ogg b/data/sounds/effects/Unlock.ogg
new file mode 100644
index 0000000..26d5ea6
--- /dev/null
+++ b/data/sounds/effects/Unlock.ogg
Binary files differ
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index bd3113b..6d1685b 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -472,10 +472,12 @@
             // First, try to use the buffer as an EGLImage directly
             if (mUseEGLImageDirectly) {
                 // NOTE: Assume the buffer is allocated with the proper USAGE flags
+
                 sp<GraphicBuffer> buffer = new  GraphicBuffer(
                         src.img.w, src.img.h, src.img.format,
                         GraphicBuffer::USAGE_HW_TEXTURE,
                         src.img.w, src.img.handle, false);
+
                 err = mLayer.initializeEglImage(buffer, &mTexture);
                 if (err != NO_ERROR) {
                     mUseEGLImageDirectly = false;
@@ -563,33 +565,27 @@
     }
 
     // Allocate a temporary buffer and create the corresponding EGLImageKHR
-
-    status_t err;
-    mTempGraphicBuffer.clear();
-    mTempGraphicBuffer = new GraphicBuffer(
+    // once the EGLImage has been created we don't need the
+    // graphic buffer reference anymore.
+    sp<GraphicBuffer> buffer = new GraphicBuffer(
             w, h, HAL_PIXEL_FORMAT_RGB_565,
             GraphicBuffer::USAGE_HW_TEXTURE |
             GraphicBuffer::USAGE_HW_2D);
 
-    err = mTempGraphicBuffer->initCheck();
+    status_t err = buffer->initCheck();
     if (err == NO_ERROR) {
         NativeBuffer& dst(mTempBuffer);
-        dst.img.w = mTempGraphicBuffer->getStride();
+        dst.img.w = buffer->getStride();
         dst.img.h = h;
-        dst.img.format = mTempGraphicBuffer->getPixelFormat();
-        dst.img.handle = (native_handle_t *)mTempGraphicBuffer->handle;
+        dst.img.format = buffer->getPixelFormat();
+        dst.img.handle = (native_handle_t *)buffer->handle;
         dst.img.base = 0;
         dst.crop.l = 0;
         dst.crop.t = 0;
         dst.crop.r = w;
         dst.crop.b = h;
 
-        err = mLayer.initializeEglImage(
-                mTempGraphicBuffer, &mTexture);
-        // once the EGLImage has been created (whether it fails
-        // or not) we don't need the graphic buffer reference
-        // anymore.
-        mTempGraphicBuffer.clear();
+        err = mLayer.initializeEglImage(buffer, &mTexture);
     }
 
     return err;
@@ -606,9 +602,6 @@
     Texture defaultTexture;
     mTexture = defaultTexture;
     mTexture.name = mLayer.createTexture();
-
-    // and the associated buffer
-    mTempGraphicBuffer.clear();
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 3257b76..eb5b8eb 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -144,7 +144,6 @@
         size_t                          mBufferSize;
         mutable LayerBase::Texture      mTexture;
         mutable NativeBuffer            mTempBuffer;
-        mutable sp<GraphicBuffer>       mTempGraphicBuffer;
         mutable bool                    mUseEGLImageDirectly;
     };
     
diff --git a/media/java/android/media/DecoderCapabilities.java b/media/java/android/media/DecoderCapabilities.java
new file mode 100644
index 0000000..f16cccf
--- /dev/null
+++ b/media/java/android/media/DecoderCapabilities.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * {@hide}
+ *
+ * The DecoderCapabilities class is used to retrieve the types of the
+ * video and audio decoder(s) supported on a specific Android platform.
+ */
+public class DecoderCapabilities
+{
+    /**
+     * The VideoDecoder class represents the type of a video decoder
+     *
+     */
+    public enum VideoDecoder {
+        VIDEO_DECODER_WMV,
+    };
+
+    /**
+     * The AudioDecoder class represents the type of an audio decoder
+     */
+    public enum AudioDecoder {
+        AUDIO_DECODER_WMA,
+    };
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    /**
+     * Returns the list of video decoder types
+     * @see android.media.DecoderCapabilities.VideoDecoder
+     */
+    public static List<VideoDecoder> getVideoDecoders() {
+        List<VideoDecoder> decoderList = new ArrayList<VideoDecoder>();
+        int nDecoders = native_get_num_video_decoders();
+        for (int i = 0; i < nDecoders; ++i) {
+            decoderList.add(VideoDecoder.values()[native_get_video_decoder_type(i)]);
+        }
+        return decoderList;
+    }
+
+    /**
+     * Returns the list of audio decoder types
+     * @see android.media.DecoderCapabilities.AudioDecoder
+     */
+    public static List<AudioDecoder> getAudioDecoders() {
+        List<AudioDecoder> decoderList = new ArrayList<AudioDecoder>();
+        int nDecoders = native_get_num_audio_decoders();
+        for (int i = 0; i < nDecoders; ++i) {
+            decoderList.add(AudioDecoder.values()[native_get_audio_decoder_type(i)]);
+        }
+        return decoderList;
+    }
+
+    private DecoderCapabilities() {}  // Don't call me
+
+    // Implemented by JNI
+    private static native final void native_init();
+    private static native final int native_get_num_video_decoders();
+    private static native final int native_get_video_decoder_type(int index);
+    private static native final int native_get_num_audio_decoders();
+    private static native final int native_get_audio_decoder_type(int index);
+}
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 50380c1..19132c5 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -44,14 +44,14 @@
     }
 }
 
-static int
+static jint
 android_media_MediaProfiles_native_get_num_file_formats(JNIEnv *env, jobject thiz)
 {
     LOGV("native_get_num_file_formats");
     return sProfiles->getOutputFileFormats().size();
 }
 
-static int
+static jint
 android_media_MediaProfiles_native_get_file_format(JNIEnv *env, jobject thiz, jint index)
 {
     LOGV("native_get_file_format: %d", index);
@@ -61,11 +61,10 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
         return -1;
     }
-    int format = static_cast<int>(formats[index]);
-    return format;
+    return static_cast<jint>(formats[index]);
 }
 
-static int
+static jint
 android_media_MediaProfiles_native_get_num_video_encoders(JNIEnv *env, jobject thiz)
 {
     LOGV("native_get_num_video_encoders");
@@ -116,7 +115,7 @@
     return cap;
 }
 
-static int
+static jint
 android_media_MediaProfiles_native_get_num_audio_encoders(JNIEnv *env, jobject thiz)
 {
     LOGV("native_get_num_audio_encoders");
@@ -209,6 +208,48 @@
                           audioChannels);
 }
 
+static jint
+android_media_MediaProfiles_native_get_num_video_decoders(JNIEnv *env, jobject thiz)
+{
+    LOGV("native_get_num_video_decoders");
+    return sProfiles->getVideoDecoders().size();
+}
+
+static jint
+android_media_MediaProfiles_native_get_video_decoder_type(JNIEnv *env, jobject thiz, jint index)
+{
+    LOGV("native_get_video_decoder_type: %d", index);
+    Vector<video_decoder> decoders = sProfiles->getVideoDecoders();
+    int nSize = decoders.size();
+    if (index < 0 || index >= nSize) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
+        return -1;
+    }
+
+    return static_cast<jint>(decoders[index]);
+}
+
+static jint
+android_media_MediaProfiles_native_get_num_audio_decoders(JNIEnv *env, jobject thiz)
+{
+    LOGV("native_get_num_audio_decoders");
+    return sProfiles->getAudioDecoders().size();
+}
+
+static jint
+android_media_MediaProfiles_native_get_audio_decoder_type(JNIEnv *env, jobject thiz, jint index)
+{
+    LOGV("native_get_audio_decoder_type: %d", index);
+    Vector<audio_decoder> decoders = sProfiles->getAudioDecoders();
+    int nSize = decoders.size();
+    if (index < 0 || index >= nSize) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
+        return -1;
+    }
+
+    return static_cast<jint>(decoders[index]);
+}
+
 static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_file_formats",            "()I",                    (void *)android_media_MediaProfiles_native_get_num_file_formats},
@@ -229,7 +270,16 @@
                                                                          (void *)android_media_MediaProfiles_native_get_camcorder_profile},
 };
 
+static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
+    {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
+    {"native_get_num_video_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_video_decoders},
+    {"native_get_num_audio_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_audio_decoders},
+    {"native_get_video_decoder_type",          "(I)I",                   (void *)android_media_MediaProfiles_native_get_video_decoder_type},
+    {"native_get_audio_decoder_type",          "(I)I",                   (void *)android_media_MediaProfiles_native_get_audio_decoder_type},
+};
+
 static const char* const kEncoderCapabilitiesClassPathName = "android/media/EncoderCapabilities";
+static const char* const kDecoderCapabilitiesClassPathName = "android/media/DecoderCapabilities";
 static const char* const kCamcorderProfileClassPathName = "android/media/CamcorderProfile";
 
 // This function only registers the native methods, and is called from
@@ -246,6 +296,11 @@
                gMethodsForCamcorderProfileClass,
                NELEM(gMethodsForCamcorderProfileClass));
 
-    // Success if ret1 == 0 && ret2 == 0
-    return (ret1 || ret2);
+    int ret3 = AndroidRuntime::registerNativeMethods(env,
+               kDecoderCapabilitiesClassPathName,
+               gMethodsForDecoderCapabilitiesClass,
+               NELEM(gMethodsForDecoderCapabilitiesClass));
+
+    // Success if ret1 == 0 && ret2 == 0 && ret3 == 0
+    return (ret1 || ret2 || ret3);
 }
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 3193d5e..2a16d26 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -225,27 +225,32 @@
         return ERROR_IO;
     }
 
-    MediaBuffer *buffer;
-    status_t err = mGroup->acquire_buffer(&buffer);
-    if (err != OK) {
-        return err;
-    }
-
     if (header & 0x83) {
         // Padding bits must be 0.
 
+        LOGE("padding bits must be 0, header is 0x%02x", header);
+
         return ERROR_MALFORMED;
     }
 
     unsigned FT = (header >> 3) & 0x0f;
 
     if (FT > 8 || (!mIsWide && FT > 7)) {
+
+        LOGE("illegal AMR frame type %d", FT);
+
         return ERROR_MALFORMED;
     }
 
     size_t frameSize = getFrameSize(mIsWide, FT);
     CHECK_EQ(frameSize, mFrameSize);
 
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
     n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
 
     if (n != (ssize_t)frameSize) {
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 4b630b9..bf020e9 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "HTTPDataSource"
+#include <utils/Log.h>
+
 #include "include/stagefright_string.h"
 #include "include/HTTPStream.h"
 
@@ -266,6 +270,8 @@
 }
 
 ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
+    LOGV("readAt %ld, size %d", offset, size);
+
     if (offset >= mBufferOffset
             && offset < (off_t)(mBufferOffset + mBufferLength)) {
         size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
@@ -298,6 +304,15 @@
 
     mBufferOffset = offset;
 
+    if (mContentLengthValid
+            && mBufferOffset + contentLength >= mContentLength) {
+        // If we never triggered a range request but know the content length,
+        // make sure to not read more data than there could be, otherwise
+        // we'd block indefinitely if the server doesn't close the connection.
+
+        contentLength = mContentLength - mBufferOffset;
+    }
+
     if (contentLength <= 0) {
         return contentLength;
     }
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 3711acac..2c5da68 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -276,11 +276,11 @@
             }
 
             disconnect();
-            return total == 0 ? ERROR_IO : total;
+            return total == 0 ? (ssize_t)ERROR_IO : total;
         } else if (n == 0) {
             disconnect();
 
-            return total == 0 ? ERROR_CONNECTION_LOST : total;
+            return total == 0 ? (ssize_t)ERROR_CONNECTION_LOST : total;
         }
 
         total += (size_t)n;
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index cb03979..76ca77b 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -128,46 +128,52 @@
 
 void Prefetcher::threadFunc() {
     for (;;) {
-        Mutex::Autolock autoLock(mLock);
-        if (mDone) {
-            break;
-        }
-        mCondition.waitRelative(mLock, 10000000ll);
+        sp<PrefetchedSource> minSource;
 
-        int64_t minCacheDurationUs = -1;
-        ssize_t minIndex = -1;
-        for (size_t i = 0; i < mSources.size(); ++i) {
-            sp<PrefetchedSource> source = mSources[i].promote();
+        {
+            Mutex::Autolock autoLock(mLock);
+            if (mDone) {
+                break;
+            }
+            mCondition.waitRelative(mLock, 10000000ll);
 
-            if (source == NULL) {
+            int64_t minCacheDurationUs = -1;
+            ssize_t minIndex = -1;
+            for (size_t i = 0; i < mSources.size(); ++i) {
+                sp<PrefetchedSource> source = mSources[i].promote();
+
+                if (source == NULL) {
+                    continue;
+                }
+
+                int64_t cacheDurationUs;
+                if (!source->getCacheDurationUs(&cacheDurationUs)) {
+                    continue;
+                }
+
+                if (cacheDurationUs >= kMaxCacheDurationUs) {
+                    continue;
+                }
+
+                if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
+                    minCacheDurationUs = cacheDurationUs;
+                    minIndex = i;
+                    minSource = source;
+                }
+            }
+
+            if (minIndex < 0) {
                 continue;
             }
-
-            int64_t cacheDurationUs;
-            if (!source->getCacheDurationUs(&cacheDurationUs)) {
-                continue;
-            }
-
-            if (cacheDurationUs >= kMaxCacheDurationUs) {
-                continue;
-            }
-
-            if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
-                minCacheDurationUs = cacheDurationUs;
-                minIndex = i;
-            }
         }
 
-        if (minIndex < 0) {
-            continue;
-        }
-
-        sp<PrefetchedSource> source = mSources[minIndex].promote();
-        if (source != NULL) {
-            source->cacheMore();
-        }
+        // Make sure not to hold the lock while calling into the source.
+        // The lock guards the list of sources, not the individual sources
+        // themselves.
+        minSource->cacheMore();
     }
 
+    Mutex::Autolock autoLock(mLock);
     for (size_t i = 0; i < mSources.size(); ++i) {
         sp<PrefetchedSource> source = mSources[i].promote();
 
diff --git a/mms-common/java/com/android/mmscommon/mms/pdu/Base64.java b/mms-common/java/com/android/mmscommon/mms/pdu/Base64.java
deleted file mode 100644
index 4c95dec..0000000
--- a/mms-common/java/com/android/mmscommon/mms/pdu/Base64.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2007 Esmertec AG.
- * Copyright (C) 2007 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.mmscommon.mms.pdu;
-
-public class Base64 {
-    /**
-     * Used to get the number of Quadruples.
-     */
-    static final int FOURBYTE = 4;
-
-    /**
-     * Byte used to pad output.
-     */
-    static final byte PAD = (byte) '=';
-
-    /**
-     * The base length.
-     */
-    static final int BASELENGTH = 255;
-
-    // Create arrays to hold the base64 characters
-    private static byte[] base64Alphabet = new byte[BASELENGTH];
-
-    // Populating the character arrays
-    static {
-        for (int i = 0; i < BASELENGTH; i++) {
-            base64Alphabet[i] = (byte) -1;
-        }
-        for (int i = 'Z'; i >= 'A'; i--) {
-            base64Alphabet[i] = (byte) (i - 'A');
-        }
-        for (int i = 'z'; i >= 'a'; i--) {
-            base64Alphabet[i] = (byte) (i - 'a' + 26);
-        }
-        for (int i = '9'; i >= '0'; i--) {
-            base64Alphabet[i] = (byte) (i - '0' + 52);
-        }
-
-        base64Alphabet['+'] = 62;
-        base64Alphabet['/'] = 63;
-    }
-
-    /**
-     * Decodes Base64 data into octects
-     *
-     * @param base64Data Byte array containing Base64 data
-     * @return Array containing decoded data.
-     */
-    public static byte[] decodeBase64(byte[] base64Data) {
-        // RFC 2045 requires that we discard ALL non-Base64 characters
-        base64Data = discardNonBase64(base64Data);
-
-        // handle the edge case, so we don't have to worry about it later
-        if (base64Data.length == 0) {
-            return new byte[0];
-        }
-
-        int numberQuadruple = base64Data.length / FOURBYTE;
-        byte decodedData[] = null;
-        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
-
-        // Throw away anything not in base64Data
-
-        int encodedIndex = 0;
-        int dataIndex = 0;
-        {
-            // this sizes the output array properly - rlw
-            int lastData = base64Data.length;
-            // ignore the '=' padding
-            while (base64Data[lastData - 1] == PAD) {
-                if (--lastData == 0) {
-                    return new byte[0];
-                }
-            }
-            decodedData = new byte[lastData - numberQuadruple];
-        }
-
-        for (int i = 0; i < numberQuadruple; i++) {
-            dataIndex = i * 4;
-            marker0 = base64Data[dataIndex + 2];
-            marker1 = base64Data[dataIndex + 3];
-
-            b1 = base64Alphabet[base64Data[dataIndex]];
-            b2 = base64Alphabet[base64Data[dataIndex + 1]];
-
-            if (marker0 != PAD && marker1 != PAD) {
-                //No PAD e.g 3cQl
-                b3 = base64Alphabet[marker0];
-                b4 = base64Alphabet[marker1];
-
-                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
-                decodedData[encodedIndex + 1] =
-                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
-                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
-            } else if (marker0 == PAD) {
-                //Two PAD e.g. 3c[Pad][Pad]
-                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
-            } else if (marker1 == PAD) {
-                //One PAD e.g. 3cQ[Pad]
-                b3 = base64Alphabet[marker0];
-
-                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
-                decodedData[encodedIndex + 1] =
-                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
-            }
-            encodedIndex += 3;
-        }
-        return decodedData;
-    }
-
-    /**
-     * Check octect wheter it is a base64 encoding.
-     *
-     * @param octect to be checked byte
-     * @return ture if it is base64 encoding, false otherwise.
-     */
-    private static boolean isBase64(byte octect) {
-        if (octect == PAD) {
-            return true;
-        } else if (base64Alphabet[octect] == -1) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    /**
-     * Discards any characters outside of the base64 alphabet, per
-     * the requirements on page 25 of RFC 2045 - "Any characters
-     * outside of the base64 alphabet are to be ignored in base64
-     * encoded data."
-     *
-     * @param data The base-64 encoded data to groom
-     * @return The data, less non-base64 characters (see RFC 2045).
-     */
-    static byte[] discardNonBase64(byte[] data) {
-        byte groomedData[] = new byte[data.length];
-        int bytesCopied = 0;
-
-        for (int i = 0; i < data.length; i++) {
-            if (isBase64(data[i])) {
-                groomedData[bytesCopied++] = data[i];
-            }
-        }
-
-        byte packedData[] = new byte[bytesCopied];
-
-        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
-
-        return packedData;
-    }
-}
diff --git a/mms-common/java/com/android/mmscommon/mms/pdu/PduParser.java b/mms-common/java/com/android/mmscommon/mms/pdu/PduParser.java
index 9253f83..6a58ba6 100644
--- a/mms-common/java/com/android/mmscommon/mms/pdu/PduParser.java
+++ b/mms-common/java/com/android/mmscommon/mms/pdu/PduParser.java
@@ -17,14 +17,15 @@
 
 package com.android.mmscommon.mms.pdu;
 
-import com.android.mmscommon.ContentType;
 import com.android.mmscommon.CharacterSets;
+import com.android.mmscommon.ContentType;
 import com.android.mmscommon.EncodedStringValue;
 import com.android.mmscommon.InvalidHeaderValueException;
 import com.android.mmscommon.PduHeaders;
 
 import android.util.Config;
 import android.util.Log;
+import android.util.base64.Base64;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -790,7 +791,7 @@
                     String encoding = new String(partDataEncoding);
                     if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) {
                         // Decode "base64" into "binary".
-                        partData = Base64.decodeBase64(partData);
+                        partData = Base64.decode(partData, Base64.DEFAULT);
                     } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) {
                         // Decode "quoted-printable" into "binary".
                         partData = QuotedPrintable.decodeQuotedPrintable(partData);
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 5ec72df..078daa7 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -6,6 +6,7 @@
     <uses-permission android:name="android.permission.ASEC_DESTROY"/>
     <uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
 
     <application android:label="@string/service_name">
 
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index c418ccb..933a7e5 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -1,22 +1,23 @@
 package com.android.defcontainer;
 
 import com.android.internal.app.IMediaContainerService;
-
+import com.android.internal.content.PackageHelper;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Package;
 import android.net.Uri;
-import android.os.Debug;
 import android.os.Environment;
 import android.os.IBinder;
-import android.os.storage.IMountService;
-import android.os.storage.StorageResultCode;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StatFs;
 import android.app.IntentService;
-import android.app.Service;
+import android.util.DisplayMetrics;
 import android.util.Log;
 
 import java.io.File;
@@ -25,9 +26,9 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 import android.os.FileUtils;
+import android.provider.Settings;
 
 /*
  * This service copies a downloaded apk to a file passed in as
@@ -45,7 +46,7 @@
          * Creates a new container and copies resource there.
          * @param paackageURI the uri of resource to be copied. Can be either
          * a content uri or a file uri
-         * @param containerId the id of the secure container that should
+         * @param cid the id of the secure container that should
          * be used for creating a secure container into which the resource
          * will be copied.
          * @param key Refers to key used for encrypting the secure container
@@ -55,12 +56,12 @@
          *
          */
         public String copyResourceToContainer(final Uri packageURI,
-                final String containerId,
+                final String cid,
                 final String key, final String resFileName) {
-            if (packageURI == null || containerId == null) {
+            if (packageURI == null || cid == null) {
                 return null;
             }
-            return copyResourceInner(packageURI, containerId, key, resFileName);
+            return copyResourceInner(packageURI, cid, key, resFileName);
         }
 
         /*
@@ -79,6 +80,44 @@
             autoOut = new ParcelFileDescriptor.AutoCloseOutputStream(outStream);
             return copyFile(packageURI, autoOut);
         }
+
+        /*
+         * Determine the recommended install location for package
+         * specified by file uri location.
+         * @param fileUri the uri of resource to be copied. Should be a
+         * file uri
+         * @return Returns
+         *  PackageHelper.RECOMMEND_INSTALL_INTERNAL to install on internal storage
+         *  PackageHelper.RECOMMEND_INSTALL_EXTERNAL to install on external media
+         *  PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE for storage errors
+         *  PackageHelper.RECOMMEND_FAILED_INVALID_APK for parse errors.
+         */
+        public int getRecommendedInstallLocation(final Uri fileUri) {
+            if (!fileUri.getScheme().equals("file")) {
+                Log.w(TAG, "Falling back to installing on internal storage only");
+                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+            }
+            final String archiveFilePath = fileUri.getPath();
+            PackageParser packageParser = new PackageParser(archiveFilePath);
+            File sourceFile = new File(archiveFilePath);
+            DisplayMetrics metrics = new DisplayMetrics();
+            metrics.setToDefaults();
+            PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+            if (pkg == null) {
+                Log.w(TAG, "Failed to parse package");
+                return PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+            }
+            int loc = recommendAppInstallLocation(pkg);
+            if (loc == PackageManager.INSTALL_EXTERNAL) {
+                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+            } else if (loc == ERR_LOC) {
+                Log.i(TAG, "Failed to install insufficient storage");
+                return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+            } else {
+                // Implies install on internal storage.
+                return 0;
+            }
+        }
     };
 
     public DefaultContainerService() {
@@ -111,7 +150,6 @@
                 }
             }
         }
-        //Log.i(TAG, "Deleting: " + path);
         path.delete();
     }
     
@@ -119,13 +157,10 @@
         return mBinder;
     }
 
-    private IMountService getMountService() {
-        return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-    }
-
-    private String copyResourceInner(Uri packageURI, String newCacheId, String key, String resFileName) {
+    private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName) {
         // Create new container at newCachePath
         String codePath = packageURI.getPath();
+        File codeFile = new File(codePath);
         String newCachePath = null;
         final int CREATE_FAILED = 1;
         final int COPY_FAILED = 2;
@@ -133,8 +168,9 @@
         final int PASS = 4;
         int errCode = CREATE_FAILED;
         // Create new container
-        if ((newCachePath = createSdDir(packageURI, newCacheId, key)) != null) {
-            if (localLOGV) Log.i(TAG, "Created container for " + newCacheId
+        if ((newCachePath = PackageHelper.createSdDir(codeFile,
+                newCid, key, Process.myUid())) != null) {
+            if (localLOGV) Log.i(TAG, "Created container for " + newCid
                     + " at path : " + newCachePath);
             File resFile = new File(newCachePath, resFileName);
             errCode = COPY_FAILED;
@@ -142,7 +178,8 @@
             if (FileUtils.copyFile(new File(codePath), resFile)) {
                 if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
                 errCode = FINALIZE_FAILED;
-                if (finalizeSdDir(newCacheId)) {
+                if (PackageHelper.finalizeSdDir(newCid)) {
+                    if (localLOGV) Log.i(TAG, "Finalized container " + newCid);
                     errCode = PASS;
                 }
             }
@@ -155,21 +192,25 @@
                 break;
             case COPY_FAILED:
                 errMsg = "COPY_FAILED";
-                if (localLOGV) Log.i(TAG, "Destroying " + newCacheId +
+                if (localLOGV) Log.i(TAG, "Destroying " + newCid +
                         " at path " + newCachePath + " after " + errMsg);
-                destroySdDir(newCacheId);
+                PackageHelper.destroySdDir(newCid);
                 break;
             case FINALIZE_FAILED:
                 errMsg = "FINALIZE_FAILED";
-                if (localLOGV) Log.i(TAG, "Destroying " + newCacheId +
+                if (localLOGV) Log.i(TAG, "Destroying " + newCid +
                         " at path " + newCachePath + " after " + errMsg);
-                destroySdDir(newCacheId);
+                PackageHelper.destroySdDir(newCid);
                 break;
             default:
                 errMsg = "PASS";
-            if (localLOGV) Log.i(TAG, "Unmounting " + newCacheId +
-                    " at path " + newCachePath + " after " + errMsg);
-                unMountSdDir(newCacheId);
+                if (PackageHelper.isContainerMounted(newCid)) {
+                    if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
+                            " at path " + newCachePath + " after " + errMsg);
+                    PackageHelper.unMountSdDir(newCid);
+                } else {
+                    if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
+                }
                 break;
         }
         if (errCode != PASS) {
@@ -178,102 +219,6 @@
         return newCachePath;
     }
 
-    private String createSdDir(final Uri packageURI,
-            String containerId, String sdEncKey) {
-        File tmpPackageFile = new File(packageURI.getPath());
-        // Create mount point via MountService
-        IMountService mountService = getMountService();
-        long len = tmpPackageFile.length();
-        int mbLen = (int) (len/(1024*1024));
-        if ((len - (mbLen * 1024 * 1024)) > 0) {
-            mbLen++;
-        }
-        if (localLOGV) Log.i(TAG, "mbLen=" + mbLen);
-        String cachePath = null;
-        int ownerUid = Process.myUid();
-        try {
-            int rc = mountService.createSecureContainer(
-                    containerId, mbLen, "vfat", sdEncKey, ownerUid);
-
-            if (rc != StorageResultCode.OperationSucceeded) {
-                Log.e(TAG, String.format("Container creation failed (%d)", rc));
-
-                // XXX: This destroy should not be necessary
-                rc = mountService.destroySecureContainer(containerId);
-                if (rc != StorageResultCode.OperationSucceeded) {
-                    Log.e(TAG, String.format("Container creation-cleanup failed (%d)", rc));
-                    return null;
-                }
-
-                // XXX: Does this ever actually succeed?
-                rc = mountService.createSecureContainer(
-                        containerId, mbLen, "vfat", sdEncKey, ownerUid);
-                if (rc != StorageResultCode.OperationSucceeded) {
-                    Log.e(TAG, String.format("Container creation retry failed (%d)", rc));
-                }
-            }
-
-            cachePath = mountService.getSecureContainerPath(containerId);
-            if (localLOGV) Log.i(TAG, "Trying to create secure container for  "
-                    + containerId + ", cachePath =" + cachePath);
-            return cachePath;
-        } catch(RemoteException e) {
-            Log.e(TAG, "MountService not running?");
-            return null;
-        }
-    }
-
-    private boolean destroySdDir(String containerId) {
-        try {
-            // We need to destroy right away
-            getMountService().destroySecureContainer(containerId);
-            return true;
-        } catch (IllegalStateException e) {
-            Log.i(TAG, "Failed to destroy container : " + containerId);
-        } catch(RemoteException e) {
-            Log.e(TAG, "MountService not running?");
-        }
-        return false;
-    }
-
-    private boolean finalizeSdDir(String containerId){
-        try {
-            getMountService().finalizeSecureContainer(containerId);
-            return true;
-        } catch (IllegalStateException e) {
-            Log.i(TAG, "Failed to finalize container for pkg : " + containerId);
-        } catch(RemoteException e) {
-            Log.e(TAG, "MountService not running?");
-        }
-        return false;
-    }
-
-    private boolean unMountSdDir(String containerId) {
-        try {
-            getMountService().unmountSecureContainer(containerId);
-            return true;
-        } catch (IllegalStateException e) {
-            Log.e(TAG, "Failed to unmount id:  " + containerId + " with exception " + e);
-        } catch(RemoteException e) {
-            Log.e(TAG, "MountService not running?");
-        }
-        return false;
-    }
-
-    private String mountSdDir(String containerId, String key) {
-        try {
-            int rc = getMountService().mountSecureContainer(containerId, key, Process.myUid());
-            if (rc == StorageResultCode.OperationSucceeded) {
-                return getMountService().getSecureContainerPath(containerId);
-            } else {
-                Log.e(TAG, String.format("Failed to mount id %s with rc %d ", containerId, rc));
-            }
-        } catch(RemoteException e) {
-            Log.e(TAG, "MountService not running?");
-        }
-        return null;
-    }
-
     public static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
         try {
             byte[] buffer = new byte[4096];
@@ -341,4 +286,103 @@
         }
         return true;
     }
+
+    // Constants related to app heuristics
+    // No-installation limit for internal flash: 10% or less space available
+    private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;
+
+    // SD-to-internal app size threshold: currently set to 1 MB
+    private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
+    private static final int ERR_LOC = -1;
+
+    public int recommendAppInstallLocation(Package pkg) {
+        // Initial implementation:
+        // Package size = code size + cache size + data size
+        // If code size > 1 MB, install on SD card.
+        // Else install on internal NAND flash, unless space on NAND is less than 10%
+
+        if (pkg == null) {
+            return ERR_LOC;
+        }
+
+        StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath());
+        StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
+
+        long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() *
+                (long)internalFlashStats.getBlockSize();
+        long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() *
+                (long)internalFlashStats.getBlockSize();
+        long availSDSize = (long)sdcardStats.getAvailableBlocks() *
+                (long)sdcardStats.getBlockSize();
+
+        double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;
+
+        final String archiveFilePath = pkg.mScanPath;
+        File apkFile = new File(archiveFilePath);
+        long pkgLen = apkFile.length();
+
+        boolean auto = true;
+        // To make final copy
+        long reqInstallSize = pkgLen;
+        // For dex files
+        long reqInternalSize = 1 * pkgLen;
+        boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
+        boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
+        boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
+                (reqInternalSize < availInternalFlashSize);
+        boolean fitsOnInt = intThresholdOk && intAvailOk;
+
+        // Consider application flags preferences as well...
+        boolean installOnlyOnSd = (pkg.installLocation ==
+                PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
+        boolean installOnlyInternal = (pkg.installLocation ==
+                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+        if (installOnlyInternal) {
+            // If set explicitly in manifest,
+            // let that override everything else
+            auto = false;
+        } else if (installOnlyOnSd){
+            // Check if this can be accommodated on the sdcard
+            if (fitsOnSd) {
+                auto = false;
+            }
+        } else {
+            // Check if user option is enabled
+            boolean setInstallLoc = Settings.System.getInt(getApplicationContext()
+                    .getContentResolver(),
+                    Settings.System.SET_INSTALL_LOCATION, 0) != 0;
+            if (setInstallLoc) {
+                // Pick user preference
+                int installPreference = Settings.System.getInt(getApplicationContext()
+                        .getContentResolver(),
+                        Settings.System.DEFAULT_INSTALL_LOCATION,
+                        PackageInfo.INSTALL_LOCATION_AUTO);
+                if (installPreference == 1) {
+                    installOnlyInternal = true;
+                    auto = false;
+                } else if (installPreference == 2) {
+                    installOnlyOnSd = true;
+                    auto = false;
+                }
+            }
+        }
+        if (!auto) {
+            if (installOnlyOnSd) {
+                return fitsOnSd ? PackageManager.INSTALL_EXTERNAL : ERR_LOC;
+            } else if (installOnlyInternal){
+                // Check on internal flash
+                return fitsOnInt ? 0 : ERR_LOC;
+            }
+        }
+        // Try to install internally
+        if (fitsOnInt) {
+            return 0;
+        }
+        // Try the sdcard now.
+        if (fitsOnSd) {
+            return PackageManager.INSTALL_EXTERNAL;
+        }
+        // Return error code
+        return ERR_LOC;
+    }
 }
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index ba6024f..654ca32 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -58,4 +58,16 @@
     <bool name="def_mount_ums_notify_enabled">true</bool>
     <bool name="set_install_location">true</bool>
 
+    <!-- user interface sound effects -->
+    <integer name="def_power_sounds_enabled">1</integer>
+    <string name="def_low_battery_sound">/system/media/ui/LowBattery.ogg</string>
+    <integer name="def_dock_sounds_enabled">1</integer>
+    <string name="def_desk_dock_sound">/system/media/audio/ui/dock.ogg</string>
+    <string name="def_desk_undock_sound">/system/media/audio/ui/undock.ogg</string>
+    <string name="def_car_dock_sound">/system/media/audio/ui/Dock.ogg</string>
+    <string name="def_car_undock_sound">/system/media/audio/ui/Undock.ogg</string>
+    <integer name="def_lockscreen_sounds_enabled">1</integer>
+    <string name="def_lock_sound">/system/media/audio/ui/Lock.ogg</string>
+    <string name="def_unlock_sound">/system/media/audio/ui/Unlock.ogg</string>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 57503f7..cf34d4e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -76,7 +76,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 49;
+    private static final int DATABASE_VERSION = 50;
 
     private Context mContext;
 
@@ -633,6 +633,24 @@
            upgradeVersion = 49;
        }
 
+       if (upgradeVersion == 49) {
+           /*
+            * New settings for new user interface noises.
+            */
+           db.beginTransaction();
+           try {
+                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadUISoundEffectsSettings(stmt);
+                stmt.close();
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+
+           upgradeVersion = 50;
+       }
+
        if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
@@ -894,9 +912,37 @@
         loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION, R.bool.set_install_location);
         loadSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
                 PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+
+        loadUISoundEffectsSettings(stmt);
+
         stmt.close();
     }
 
+    private void loadUISoundEffectsSettings(SQLiteStatement stmt) {
+        loadIntegerSetting(stmt, Settings.System.POWER_SOUNDS_ENABLED,
+            R.integer.def_power_sounds_enabled);
+        loadStringSetting(stmt, Settings.System.LOW_BATTERY_SOUND,
+            R.string.def_low_battery_sound);
+
+        loadIntegerSetting(stmt, Settings.System.DOCK_SOUNDS_ENABLED,
+            R.integer.def_dock_sounds_enabled);
+        loadStringSetting(stmt, Settings.System.DESK_DOCK_SOUND,
+            R.string.def_desk_dock_sound);
+        loadStringSetting(stmt, Settings.System.DESK_UNDOCK_SOUND,
+            R.string.def_desk_undock_sound);
+        loadStringSetting(stmt, Settings.System.CAR_DOCK_SOUND,
+            R.string.def_car_dock_sound);
+        loadStringSetting(stmt, Settings.System.CAR_UNDOCK_SOUND,
+            R.string.def_car_undock_sound);
+
+        loadIntegerSetting(stmt, Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
+            R.integer.def_lockscreen_sounds_enabled);
+        loadStringSetting(stmt, Settings.System.LOCK_SOUND,
+            R.string.def_lock_sound);
+        loadStringSetting(stmt, Settings.System.UNLOCK_SOUND,
+            R.string.def_unlock_sound);
+    }
+
     private void loadDefaultAnimationSettings(SQLiteStatement stmt) {
         loadFractionSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE,
                 R.fraction.def_window_animation_scale, 1);
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index c907368..d280475 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -26,10 +26,14 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Binder;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
@@ -60,8 +64,11 @@
     public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4;
 
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
     private int mNightMode = MODE_NIGHT_NO;
     private boolean mCarModeEnabled = false;
+
     private boolean mSystemReady;
 
     private final Context mContext;
@@ -129,7 +136,7 @@
             try {
                 int newState = Integer.parseInt(event.get("SWITCH_STATE"));
                 if (newState != mDockState) {
-                    int oldState = mDockState;
+                    mPreviousDockState = mDockState;
                     mDockState = newState;
                     boolean carModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
                     if (mCarModeEnabled != carModeEnabled) {
@@ -143,8 +150,8 @@
                         // Don't force screen on when undocking from the desk dock.
                         // The change in power state will do this anyway.
                         // FIXME - we should be configurable.
-                        if (oldState != Intent.EXTRA_DOCK_STATE_DESK ||
-                                newState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                        if (mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK ||
+                                mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
                             mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
                                     false, true);
                         }
@@ -163,7 +170,7 @@
         try {
             FileReader file = new FileReader(DOCK_STATE_PATH);
             int len = file.read(buffer, 0, 1024);
-            mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
+            mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
 
         } catch (FileNotFoundException e) {
             Log.w(TAG, "This kernel does not have dock station support");
@@ -195,7 +202,10 @@
         public void handleMessage(Message msg) {
             synchronized (this) {
                 Log.i(TAG, "Dock state changed: " + mDockState);
-                if (Settings.Secure.getInt(mContext.getContentResolver(),
+
+                final ContentResolver cr = mContext.getContentResolver();
+
+                if (Settings.Secure.getInt(cr,
                         Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
                     Log.i(TAG, "Device not provisioned, skipping dock broadcast");
                     return;
@@ -217,6 +227,38 @@
                     intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
                             BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
 
+                // User feedback to confirm dock connection. Particularly
+                // useful for flaky contact pins...
+                if (Settings.System.getInt(cr,
+                        Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1)
+                {
+                    String whichSound = null;
+                    if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                        if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                            whichSound = Settings.System.DESK_UNDOCK_SOUND;
+                        } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                            whichSound = Settings.System.CAR_UNDOCK_SOUND;
+                        }
+                    } else {
+                        if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                            whichSound = Settings.System.DESK_DOCK_SOUND;
+                        } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                            whichSound = Settings.System.CAR_DOCK_SOUND;
+                        }
+                    }
+
+                    if (whichSound != null) {
+                        final String soundPath = Settings.System.getString(cr, whichSound);
+                        if (soundPath != null) {
+                            final Uri soundUri = Uri.parse("file://" + soundPath);
+                            if (soundUri != null) {
+                                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                                if (sfx != null) sfx.play();
+                            }
+                        }
+                    }
+                }
+
                 // Send the ordered broadcast; the result receiver will receive after all
                 // broadcasts have been sent. If any broadcast receiver changes the result
                 // code from the initial value of RESULT_OK, then the result receiver will
diff --git a/services/java/com/android/server/FallbackCheckinService.java b/services/java/com/android/server/FallbackCheckinService.java
deleted file mode 100644
index 195eb63..0000000
--- a/services/java/com/android/server/FallbackCheckinService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.ICheckinService;
-import android.os.IParentalControlCallback;
-import android.os.RecoverySystem;
-import android.util.Log;
-
-import java.io.IOException;
-
-import com.google.android.net.ParentalControlState;
-
-/**
- * @hide
- */
-public final class FallbackCheckinService extends ICheckinService.Stub {
-    static final String TAG = "FallbackCheckinService";
-    final Context mContext;
-
-    public FallbackCheckinService(Context context) {
-        mContext = context;
-    }
-
-    public void getParentalControlState(IParentalControlCallback p, String requestingApp)
-            throws android.os.RemoteException {
-        ParentalControlState state = new ParentalControlState();
-        state.isEnabled = false;
-        p.onResult(state);
-    }
-}
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 6f207e0..d3bb6dc 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -570,14 +570,14 @@
                         mDownTime = curTime;
                     } else {
                         action = MotionEvent.ACTION_POINTER_DOWN
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
                     }
                 } else {
                     if (numPointers == 1) {
                         action = MotionEvent.ACTION_UP;
                     } else {
                         action = MotionEvent.ACTION_POINTER_UP
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
                     }
                 }
                 currentMove = null;
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index ab0eb81..0417e71 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -30,7 +30,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
-            if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
+            if (!"google.com".equals(intent.getStringExtra("from"))) {
                 Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
                 return;
             }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index a5213a0..4326efc 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -20,6 +20,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.common.FastXmlSerializer;
 import com.android.common.XmlUtils;
+import com.android.internal.content.PackageHelper;
 import com.android.server.JournaledFile;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -304,6 +305,7 @@
     static final int INIT_COPY = 5;
     static final int MCS_UNBIND = 6;
     static final int START_CLEANING_PACKAGE = 7;
+    static final int FIND_INSTALL_LOC = 8;
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
     private ServiceConnection mDefContainerConn = new ServiceConnection() {
@@ -319,8 +321,8 @@
     };
 
     class PackageHandler extends Handler {
-        final ArrayList<InstallArgs> mPendingInstalls =
-            new ArrayList<InstallArgs>();
+        final ArrayList<InstallParams> mPendingInstalls =
+            new ArrayList<InstallParams>();
         // Service Connection to remote media container service to copy
         // package uri's from external media onto secure containers
         // or internal storage.
@@ -332,21 +334,20 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case INIT_COPY: {
-                    InstallArgs args = (InstallArgs) msg.obj;
-                    args.createCopyFile();
+                    InstallParams params = (InstallParams) msg.obj;
                     Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
                     if (mContainerService != null) {
                         // No need to add to pending list. Use remote stub directly
-                        handleStartCopy(args);
+                        handleStartCopy(params);
                     } else {
                         if (mContext.bindService(service, mDefContainerConn,
                                 Context.BIND_AUTO_CREATE)) {
-                            mPendingInstalls.add(args);
+                            mPendingInstalls.add(params);
                         } else {
                             Log.e(TAG, "Failed to bind to media container service");
                             // Indicate install failure TODO add new error code
-                            processPendingInstall(args,
-                                    PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE);
+                            processPendingInstall(createInstallArgs(params),
+                                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
                         }
                     }
                     break;
@@ -357,9 +358,9 @@
                         mContainerService = (IMediaContainerService) msg.obj;
                     }
                     if (mPendingInstalls.size() > 0) {
-                        InstallArgs args = mPendingInstalls.remove(0);
-                        if (args != null) {
-                            handleStartCopy(args);
+                        InstallParams params = mPendingInstalls.remove(0);
+                        if (params != null) {
+                            handleStartCopy(params);
                         }
                     }
                     break;
@@ -423,22 +424,56 @@
 
         // Utility method to initiate copying apk via media
         // container service.
-        private void handleStartCopy(InstallArgs args) {
-            int ret = PackageManager.INSTALL_SUCCEEDED;
-            if (mContainerService == null) {
-                // Install error
-                ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            } else {
-                ret = args.copyApk(mContainerService);
+        private void handleStartCopy(InstallParams params) {
+            int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            if (mContainerService != null) {
+                // Remote call to find out default install location
+                int loc = params.getInstallLocation(mContainerService);
+                // Use install location to create InstallArgs and temporary
+                // install location
+                if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+                } else {
+                    if ((params.flags & PackageManager.INSTALL_EXTERNAL) == 0){
+                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+                            // Set the flag to install on external media.
+                            params.flags |= PackageManager.INSTALL_EXTERNAL;
+                        } else {
+                            // Make sure the flag for installing on external
+                            // media is unset
+                            params.flags &= ~PackageManager.INSTALL_EXTERNAL;
+                        }
+                    }
+                    // Disable forward locked apps on sdcard.
+                    if ((params.flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 &&
+                            (params.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+                        // Make sure forward locked apps can only be installed
+                        // on internal storage
+                        Log.w(TAG, "Cannot install protected apps on sdcard");
+                        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+                    } else {
+                        ret = PackageManager.INSTALL_SUCCEEDED;
+                    }
+                }
             }
             mHandler.sendEmptyMessage(MCS_UNBIND);
+            // Create the file args now.
+            InstallArgs args = createInstallArgs(params);
+            if (ret == PackageManager.INSTALL_SUCCEEDED) {
+                // Create copy only if we are not in an erroneous state.
+                args.createCopyFile();
+                // Remote call to initiate copy
+                ret = args.copyApk(mContainerService);
+            }
             processPendingInstall(args, ret);
         }
     }
 
     static boolean installOnSd(int flags) {
         if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) ||
-                ((flags & PackageManager.INSTALL_ON_SDCARD) == 0)) {
+                ((flags & PackageManager.INSTALL_EXTERNAL) == 0)) {
             return false;
         }
         return true;
@@ -2145,10 +2180,15 @@
         int i;
         for (i=0; i<files.length; i++) {
             File file = new File(dir, files[i]);
+            if (files[i] != null && files[i].endsWith(".zip")) {
+                // Public resource for forward locked package. Ignore
+                continue;
+            }
             PackageParser.Package pkg = scanPackageLI(file,
                     flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
             // Don't mess around with apps in system partition.
-            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0) {
+            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
+                    mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
                 // Delete the apk
                 Log.w(TAG, "Cleaning up failed install of " + file);
                 file.delete();
@@ -4249,29 +4289,11 @@
                 android.Manifest.permission.INSTALL_PACKAGES, null);
 
         Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = createInstallArgs(packageURI, observer, flags, installerPackageName);
+        msg.obj = new InstallParams(packageURI, observer, flags,
+                installerPackageName);
         mHandler.sendMessage(msg);
     }
 
-    private InstallArgs createInstallArgs(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName) {
-        if (installOnSd(flags)) {
-            return new SdInstallArgs(packageURI, observer, flags,
-                    installerPackageName);
-        } else {
-            return new FileInstallArgs(packageURI, observer, flags,
-                    installerPackageName);
-        }
-    }
-
-    private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
-        if (installOnSd(flags)) {
-            return new SdInstallArgs(fullCodePath, fullResourcePath);
-        } else {
-            return new FileInstallArgs(fullCodePath, fullResourcePath);
-        }
-    }
-
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
@@ -4327,6 +4349,45 @@
         });
     }
 
+    static final class InstallParams {
+        final IPackageInstallObserver observer;
+        int flags;
+        final Uri packageURI;
+        final String installerPackageName;
+        InstallParams(Uri packageURI,
+                IPackageInstallObserver observer, int flags,
+                String installerPackageName) {
+            this.packageURI = packageURI;
+            this.flags = flags;
+            this.observer = observer;
+            this.installerPackageName = installerPackageName;
+        }
+
+        public int getInstallLocation(IMediaContainerService imcs) {
+            try {
+                return imcs.getRecommendedInstallLocation(packageURI);
+            } catch (RemoteException e) {
+            }
+            return  -1;
+        }
+    };
+
+    private InstallArgs createInstallArgs(InstallParams params) {
+        if (installOnSd(params.flags)) {
+            return new SdInstallArgs(params);
+        } else {
+            return new FileInstallArgs(params);
+        }
+    }
+
+    private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
+        if (installOnSd(flags)) {
+            return new SdInstallArgs(fullCodePath, fullResourcePath);
+        } else {
+            return new FileInstallArgs(fullCodePath, fullResourcePath);
+        }
+    }
+
     static abstract class InstallArgs {
         final IPackageInstallObserver observer;
         final int flags;
@@ -4359,10 +4420,9 @@
         String codeFileName;
         String resourceFileName;
 
-        FileInstallArgs(Uri packageURI,
-                IPackageInstallObserver observer, int flags,
-                String installerPackageName) {
-            super(packageURI, observer, flags, installerPackageName);
+        FileInstallArgs(InstallParams params) {
+            super(params.packageURI, params.observer,
+                    params.flags, params.installerPackageName);
         }
 
         FileInstallArgs(String fullCodePath, String fullResourcePath) {
@@ -4373,6 +4433,10 @@
             resourceFileName = fullResourcePath;
         }
 
+        String getCodePath() {
+            return codeFileName;
+        }
+
         void createCopyFile() {
             boolean fwdLocked = isFwdLocked(flags);
             installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
@@ -4380,10 +4444,6 @@
             resourceFileName = getResourcePathFromCodePath();
         }
 
-        String getCodePath() {
-            return codeFileName;
-        }
-
         int copyApk(IMediaContainerService imcs) {
             // Get a ParcelFileDescriptor to write to the output file
             File codeFile = new File(codeFileName);
@@ -4528,10 +4588,9 @@
         String cachePath;
         static final String RES_FILE_NAME = "pkg.apk";
 
-        SdInstallArgs(Uri packageURI,
-                IPackageInstallObserver observer, int flags,
-                String installerPackageName) {
-           super(packageURI, observer, flags, installerPackageName);
+        SdInstallArgs(InstallParams params) {
+            super(params.packageURI, params.observer,
+                    params.flags, params.installerPackageName);
         }
 
         SdInstallArgs(String fullCodePath, String fullResourcePath) {
@@ -4577,13 +4636,11 @@
         int doPreInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 // Destroy container
-                destroySdDir(cid);
+                PackageHelper.destroySdDir(cid);
             } else {
-                // STOPSHIP Remove once new api is added in MountService
-                //boolean mounted = isContainerMounted(cid);
-                boolean mounted = false;
+                boolean mounted = PackageHelper.isContainerMounted(cid);
                 if (!mounted) {
-                    cachePath = mountSdDir(cid, Process.SYSTEM_UID);
+                    cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID);
                     if (cachePath == null) {
                         return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
                     }
@@ -4596,96 +4653,41 @@
                 String oldCodePath) {
             String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
             String newCachePath = null;
-            /*final int RENAME_FAILED = 1;
+            final int RENAME_FAILED = 1;
             final int MOUNT_FAILED = 2;
-            final int DESTROY_FAILED = 3;
             final int PASS = 4;
             int errCode = RENAME_FAILED;
+            String errMsg = "RENAME_FAILED";
+            boolean mounted = PackageHelper.isContainerMounted(cid);
             if (mounted) {
                 // Unmount the container
-                if (!unMountSdDir(cid)) {
+                if (!PackageHelper.unMountSdDir(cid)) {
                     Log.i(TAG, "Failed to unmount " + cid + " before renaming");
                     return false;
                 }
                 mounted = false;
             }
-            if (renameSdDir(cid, newCacheId)) {
+            if (PackageHelper.renameSdDir(cid, newCacheId)) {
                 errCode = MOUNT_FAILED;
-                if ((newCachePath = mountSdDir(newCacheId, Process.SYSTEM_UID)) != null) {
+                errMsg = "MOUNT_FAILED";
+                if ((newCachePath = PackageHelper.mountSdDir(newCacheId,
+                        getEncryptKey(), Process.SYSTEM_UID)) != null) {
                     errCode = PASS;
+                    errMsg = "PASS";
                 }
             }
-            String errMsg = "";
-            switch (errCode) {
-                case RENAME_FAILED:
-                    errMsg = "RENAME_FAILED";
-                    break;
-                case MOUNT_FAILED:
-                    errMsg = "MOUNT_FAILED";
-                    break;
-                case DESTROY_FAILED:
-                    errMsg = "DESTROY_FAILED";
-                    break;
-                default:
-                    errMsg = "PASS";
-                break;
-            }
-            Log.i(TAG, "Status: " + errMsg);
             if (errCode != PASS) {
+                Log.i(TAG, "Failed to rename " + cid + " to " + newCacheId +
+                        " at path: " + cachePath + " to new path: " + newCachePath +
+                        "err = " + errMsg);
+                // Mount old container?
                 return false;
-            }
-            Log.i(TAG, "Succesfully renamed " + cid + " to " +newCacheId +
-                    " at path: " + cachePath + " to new path: " + newCachePath);
-            cid = newCacheId;
-            cachePath = newCachePath;
-            return true;
-            */
-            // STOPSHIP TEMPORARY HACK FOR RENAME
-            // Create new container at newCachePath
-            String codePath = getCodePath();
-            final int CREATE_FAILED = 1;
-            final int COPY_FAILED = 3;
-            final int FINALIZE_FAILED = 5;
-            final int PASS = 7;
-            int errCode = CREATE_FAILED;
-
-            if ((newCachePath = createSdDir(new File(codePath), newCacheId)) != null) {
-                errCode = COPY_FAILED;
-                // Copy file from codePath
-                if (FileUtils.copyFile(new File(codePath), new File(newCachePath, RES_FILE_NAME))) {
-                    errCode = FINALIZE_FAILED;
-                    if (finalizeSdDir(newCacheId)) {
-                        errCode = PASS;
-                    }
-                }
-            }
-            // Print error based on errCode
-            String errMsg = "";
-            switch (errCode) {
-                case CREATE_FAILED:
-                    errMsg = "CREATE_FAILED";
-                    break;
-                case COPY_FAILED:
-                    errMsg = "COPY_FAILED";
-                    destroySdDir(newCacheId);
-                    break;
-                case FINALIZE_FAILED:
-                    errMsg = "FINALIZE_FAILED";
-                    destroySdDir(newCacheId);
-                    break;
-                default:
-                    errMsg = "PASS";
-                break;
-            }
-            // Destroy the temporary container
-            destroySdDir(cid);
-            Log.i(TAG, "Status: " + errMsg);
-            if (errCode != PASS) {
-                return false;
+            } else {
+                Log.i(TAG, "Succesfully renamed " + cid + " to " + newCacheId +
+                        " at path: " + cachePath + " to new path: " + newCachePath);
             }
             cid = newCacheId;
             cachePath = newCachePath;
-
             return true;
         }
 
@@ -4693,11 +4695,10 @@
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
             } else {
-                // STOP SHIP Change this once new api is added.
-                //boolean mounted = isContainerMounted(cid);
-                boolean mounted = false;
+                boolean mounted = PackageHelper.isContainerMounted(cid);
                 if (!mounted) {
-                    mountSdDir(cid, Process.SYSTEM_UID);
+                    PackageHelper.mountSdDir(cid,
+                            getEncryptKey(), Process.myUid());
                 }
             }
             return status;
@@ -4705,7 +4706,7 @@
 
         private void cleanUp() {
             // Destroy secure container
-            destroySdDir(cid);
+            PackageHelper.destroySdDir(cid);
         }
 
         void cleanUpResourcesLI() {
@@ -4740,10 +4741,10 @@
 
         boolean doPostDeleteLI(boolean delete) {
             boolean ret = false;
-            boolean mounted = isContainerMounted(cid);
+            boolean mounted = PackageHelper.isContainerMounted(cid);
             if (mounted) {
                 // Unmount first
-                ret = unMountSdDir(cid);
+                ret = PackageHelper.unMountSdDir(cid);
             }
             if (ret && delete) {
                 cleanUpResourcesLI();
@@ -5105,7 +5106,7 @@
         String installerPackageName = args.installerPackageName;
         File tmpPackageFile = new File(args.getCodePath());
         boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
-        boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
+        boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
         boolean replace = false;
         int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
                 | (newInstall ? SCAN_NEW_INSTALL : 0);
@@ -5136,14 +5137,6 @@
             res.returnCode = pp.getParseError();
             return;
         }
-        // Some preinstall checks
-        if (forwardLocked && onSd) {
-            // Make sure forward locked apps can only be installed
-            // on internal storage
-            Log.w(TAG, "Cannot install protected apps on sdcard");
-            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
-            return;
-        }
         // Get rid of all references to package scan path via parser.
         pp = null;
         String oldCodePath = null;
@@ -5560,7 +5553,7 @@
         if (deleteCodeAndResources) {
             // TODO can pick up from PackageSettings as well
             int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD)!=0) ?
-                    PackageManager.INSTALL_ON_SDCARD : 0;
+                    PackageManager.INSTALL_EXTERNAL : 0;
             installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
                     PackageManager.INSTALL_FORWARD_LOCK : 0;
             outInfo.args = createInstallArgs(installFlags,
@@ -8544,11 +8537,6 @@
     private boolean mMediaMounted = false;
     private static final int MAX_CONTAINERS = 250;
 
-
-    static MountService getMountService() {
-        return (MountService) ServiceManager.getService("mount");
-    }
-
     private String getEncryptKey() {
         try {
             String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
@@ -8567,134 +8555,10 @@
         }
     }
 
-   private String createSdDir(File tmpPackageFile, String pkgName) {
-        // Create mount point via MountService
-        MountService mountService = getMountService();
-        long len = tmpPackageFile.length();
-        int mbLen = (int) (len/(1024*1024));
-        if ((len - (mbLen * 1024 * 1024)) > 0) {
-            mbLen++;
-        }
-        if (DEBUG_SD_INSTALL) Log.i(TAG, "mbLen="+mbLen);
-        String cachePath = null;
-        String sdEncKey;
-        try {
-            sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
-            if (sdEncKey == null) {
-                sdEncKey = SystemKeyStore.getInstance().
-                        generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
-                if (sdEncKey == null) {
-                    Log.e(TAG, "Failed to create encryption keys for package: " + pkgName + ".");
-                    return null;
-                }
-            }
-        } catch (NoSuchAlgorithmException nsae) {
-            Log.e(TAG, "Failed to create encryption keys with exception: " + nsae);
-            return null;
-        }
-
-        int rc = mountService.createSecureContainer(
-                pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
-        if (rc != StorageResultCode.OperationSucceeded) {
-            Log.e(TAG, String.format("Failed to create container (%d)", rc));
-
-            rc = mountService.destroySecureContainer(pkgName);
-            if (rc != StorageResultCode.OperationSucceeded) {
-                Log.e(TAG, String.format("Failed to cleanup container (%d)", rc));
-                return null;
-            }
-            rc = mountService.createSecureContainer(
-                    pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
-            if (rc != StorageResultCode.OperationSucceeded) {
-                Log.e(TAG, String.format("Failed to create container (2nd try) (%d)", rc));
-                return null;
-            }
-        }
-
-        cachePath = mountService.getSecureContainerPath(pkgName);
-        if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install " + pkgName + ", cachePath =" + cachePath);
-            return cachePath;
-    }
-
-   private String mountSdDir(String pkgName, int ownerUid) {
-       String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
-       if (sdEncKey == null) {
-           Log.e(TAG, "Failed to retrieve encryption keys to mount package code: " + pkgName + ".");
-           return null;
-       }
-
-       int rc = getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid);
-
-       if (rc != StorageResultCode.OperationSucceeded) {
-           Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " rc : " + rc);
-           return null;
-       }
-
-       return getMountService().getSecureContainerPath(pkgName);
-   }
-
-   private boolean unMountSdDir(String pkgName) {
-       // STOPSHIP unmount directory
-       int rc = getMountService().unmountSecureContainer(pkgName);
-       if (rc != StorageResultCode.OperationSucceeded) {
-           Log.e(TAG, "Failed to unmount : " + pkgName + " with rc " + rc);
-           return false;
-       }
-       return true;
-   }
-
-   private boolean renameSdDir(String oldId, String newId) {
-       try {
-           getMountService().renameSecureContainer(oldId, newId);
-           return true;
-       } catch (IllegalStateException e) {
-           Log.i(TAG, "Failed ot rename  " + oldId + " to " + newId +
-                   " with exception : " + e);
-       }
-       return false;
-   }
-
-   private String getSdDir(String pkgName) {
-       return getMountService().getSecureContainerPath(pkgName);
-   }
-
-    private boolean finalizeSdDir(String pkgName) {
-        int rc = getMountService().finalizeSecureContainer(pkgName);
-        if (rc != StorageResultCode.OperationSucceeded) {
-            Log.i(TAG, "Failed to finalize container for pkg : " + pkgName);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean destroySdDir(String pkgName) {
-        int rc = getMountService().destroySecureContainer(pkgName);
-        if (rc != StorageResultCode.OperationSucceeded) {
-            Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
-            return false;
-        }
-        return true;
-    }
-
-    static String[] getSecureContainerList() {
-        String[] list = getMountService().getSecureContainerList();
-        return list.length == 0 ? null : list;
-    }
-
-   static boolean isContainerMounted(String cid) {
-       // STOPSHIP
-       // New api from MountService
-       try {
-           return (getMountService().getSecureContainerPath(cid) != null);
-       } catch (IllegalStateException e) {
-       }
-       return false;
-   }
-
    static String getTempContainerId() {
        String prefix = "smdl1tmp";
        int tmpIdx = 1;
-       String list[] = getSecureContainerList();
+       String list[] = PackageHelper.getSecureContainerList();
        if (list != null) {
            int idx = 0;
            int idList[] = new int[MAX_CONTAINERS];
@@ -8753,7 +8617,7 @@
    }
 
    void updateExternalMediaStatusInner(boolean mediaStatus) {
-       final String list[] = getSecureContainerList();
+       final String list[] = PackageHelper.getSecureContainerList();
        if (list == null || list.length == 0) {
            return;
        }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6e9c21b..28b4b28 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -329,19 +329,6 @@
             }
 
             try {
-                Log.i(TAG, "Checkin Service");
-                Intent intent = new Intent().setComponent(new ComponentName(
-                        "com.google.android.server.checkin",
-                        "com.google.android.server.checkin.CheckinService"));
-                if (context.startService(intent) == null) {
-                    Log.w(TAG, "Using fallback Checkin Service.");
-                    ServiceManager.addService("checkin", new FallbackCheckinService(context));
-                }
-            } catch (Throwable e) {
-                Log.e(TAG, "Failure starting Checkin Service", e);
-            }
-
-            try {
                 Log.i(TAG, "Wallpaper Service");
                 wallpaper = new WallpaperManagerService(context);
                 ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d0f6a7c..8a73e99 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9493,7 +9493,7 @@
         String[] newArgs;
         String componentNameString;
         ServiceRecord r;
-        if (opti <= args.length) {
+        if (opti >= args.length) {
             componentNameString = null;
             newArgs = EMPTY_STRING_ARRAY;
             r = null;
@@ -13463,6 +13463,12 @@
                             app.hidden = false;
                         }
                     }
+                    // If we have let the service slide into the background
+                    // state, still have some text describing what it is doing
+                    // even though the service no longer has an impact.
+                    if (adj > SECONDARY_SERVER_ADJ) {
+                        app.adjType = "started-bg-services";
+                    }
                 }
                 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
@@ -13853,6 +13859,15 @@
 
         mAdjSeq++;
 
+        // Let's determine how many processes we have running vs.
+        // how many slots we have for background processes; we may want
+        // to put multiple processes in a slot of there are enough of
+        // them.
+        int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
+        int factor = (mLruProcesses.size()-4)/numSlots;
+        if (factor < 1) factor = 1;
+        int step = 0;
+        
         // First try updating the OOM adjustment for each of the
         // application processes based on their current state.
         int i = mLruProcesses.size();
@@ -13864,7 +13879,11 @@
             if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
                 if (curHiddenAdj < EMPTY_APP_ADJ
                     && app.curAdj == curHiddenAdj) {
-                    curHiddenAdj++;
+                    step++;
+                    if (step >= factor) {
+                        step = 0;
+                        curHiddenAdj++;
+                    }
                 }
             } else {
                 didOomAdj = false;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 20209e4..d13f9d3 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -22,6 +22,7 @@
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothPbap;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -30,7 +31,10 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
 import android.net.NetworkInfo;
+import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Handler;
@@ -109,6 +113,7 @@
     private int mBatteryViewSequence;
     private boolean mBatteryShowLowOnEndCall = false;
     private static final boolean SHOW_LOW_BATTERY_WARNING = true;
+    private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
 
     // phone
     private TelephonyManager mPhone;
@@ -686,7 +691,7 @@
                       + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
             }
 
-            if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+            if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
                 showLowBatteryWarning();
             } else {
                 mBatteryShowLowOnEndCall = true;
@@ -810,6 +815,21 @@
             d.show();
             mLowBatteryDialog = d;
         }
+
+        final ContentResolver cr = mContext.getContentResolver();
+        if (Settings.System.getInt(cr,
+                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) 
+        {
+            final String soundPath = Settings.System.getString(cr,
+                Settings.System.LOW_BATTERY_SOUND);
+            if (soundPath != null) {
+                final Uri soundUri = Uri.parse("file://" + soundPath);
+                if (soundUri != null) {
+                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                    if (sfx != null) sfx.play();
+                }
+            }
+        }
     }
 
     private final void updateCallState(int state) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index c351289..39fe007 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -1203,32 +1203,23 @@
         } else {
             int[] ints = (int[])ar.result;
             int offset = 2;
-
             int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
             int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -160;
+            int evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -120;
+            int evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1;
+            int evdoSnr  = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1;
 
-            int evdoRssi = -1;
-            int evdoEcio = -1;
-            int evdoSnr = -1;
-            if ((networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
-                    || (networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
-                evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -120;
-                evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1;
-                evdoSnr  = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1;
-            }
-
+            //log(String.format("onSignalStrengthResult cdmaDbm=%d cdmaEcio=%d evdoRssi=%d evdoEcio=%d evdoSnr=%d",
+            //        cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, evdoSnr));
             mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio,
                     evdoRssi, evdoEcio, evdoSnr, false);
         }
 
-        if (!mSignalStrength.equals(oldSignalStrength)) {
-            try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after
-                  // POLL_PERIOD_MILLIS) during Radio Technology Change)
-                phone.notifySignalStrength();
-           } catch (NullPointerException ex) {
-                log("onSignalStrengthResult() Phone already destroyed: " + ex
-                        + "SignalStrength not notified");
-           }
+        try {
+            phone.notifySignalStrength();
+        } catch (NullPointerException ex) {
+            log("onSignalStrengthResult() Phone already destroyed: " + ex
+                    + "SignalStrength not notified");
         }
     }
 
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index 2a4b3f7..f1ba44a 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -449,12 +449,4 @@
     public boolean isSafeMode() {
         throw new UnsupportedOperationException();
     }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int recommendAppInstallLocation(PackageParser.Package pkg) {
-        throw new UnsupportedOperationException();
-    }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 07bd489..8f4d0a1 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -192,6 +192,27 @@
         }
     }
 
+    public boolean invokeInstallPackageFail(Uri packageURI, int flags,
+            final String pkgName, int result) throws Exception {
+        PackageInstallObserver observer = new PackageInstallObserver();
+        try {
+            // Wait on observer
+            synchronized(observer) {
+                getPm().installPackage(packageURI, observer, flags, null);
+                long waitTime = 0;
+                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                    observer.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!observer.isDone()) {
+                    throw new Exception("Timed out waiting for packageInstalled callback");
+                }
+                return (observer.returnCode == result);
+            }
+        } finally {
+        }
+    }
+
     Uri getInstallablePackage(int fileResId, File outFile) {
         Resources res = mContext.getResources();
         InputStream is = null;
@@ -238,7 +259,7 @@
             assertEquals(publicSrcPath, appInstallPath);
         } else {
             assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
-            if ((flags & PackageManager.INSTALL_ON_SDCARD) != 0) {
+            if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
                 assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
                 // Hardcoded for now
                 assertTrue(srcPath.startsWith("/asec"));
@@ -253,6 +274,13 @@
             failStr("failed with exception : " + e);
         }
     }
+    private void assertNotInstalled(String pkgName) {
+        try {
+            ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
+            fail(pkgName + " shouldnt be installed");
+        } catch (NameNotFoundException e) {
+        }
+    }
 
     class InstallParams {
         String outFileName;
@@ -265,30 +293,42 @@
         }
     }
 
+    private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) {
+        return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
+                false, -1);
+    }
     /*
      * Utility function that reads a apk bundled as a raw resource
      * copies it into own data directory and invokes
      * PackageManager api to install it.
      */
-    public InstallParams installFromRawResource(int flags, boolean cleanUp) {
-        String outFileName = "install.apk";
+    private InstallParams installFromRawResource(String outFileName,
+            int rawResId, int flags, boolean cleanUp, boolean fail, int result) {
         File filesDir = mContext.getFilesDir();
         File outFile = new File(filesDir, outFileName);
-        Uri packageURI = getInstallablePackage(R.raw.install, outFile);
+        Uri packageURI = getInstallablePackage(rawResId, outFile);
         PackageParser.Package pkg = parsePackage(packageURI);
         assertNotNull(pkg);
-        InstallReceiver receiver = new InstallReceiver(pkg.packageName);
         InstallParams ip = null;
         try {
             try {
-                assertTrue(invokeInstallPackage(packageURI, flags,
-                        pkg.packageName, receiver));
+                if (fail) {
+                    // Make sure it doesn't exist
+                    getPm().deletePackage(pkg.packageName, null, 0);
+                    assertTrue(invokeInstallPackageFail(packageURI, flags,
+                            pkg.packageName, result));
+                    assertNotInstalled(pkg.packageName);
+                } else {
+                    InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+                    assertTrue(invokeInstallPackage(packageURI, flags,
+                            pkg.packageName, receiver));
+                    // Verify installed information
+                    assertInstall(pkg.packageName, flags);
+                    ip = new InstallParams(pkg, outFileName, packageURI);
+                }
             } catch (Exception e) {
                 failStr("Failed with exception : " + e);
             }
-            // Verify installed information
-            assertInstall(pkg.packageName, flags);
-            ip = new InstallParams(pkg, outFileName, packageURI);
             return ip;
         } finally {
             if (cleanUp) {
@@ -299,17 +339,17 @@
 
     @MediumTest
     public void testInstallNormalInternal() {
-        installFromRawResource(0, true);
+        sampleInstallFromRawResource(0, true);
     }
 
     @MediumTest
     public void testInstallFwdLockedInternal() {
-        installFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
+        sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
     }
 
     @MediumTest
     public void testInstallSdcard() {
-        installFromRawResource(PackageManager.INSTALL_ON_SDCARD, true);
+        sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true);
     }
 
     /* ------------------------- Test replacing packages --------------*/
@@ -373,7 +413,7 @@
      * again.
      */
     public void replaceFromRawResource(int flags) {
-        InstallParams ip = installFromRawResource(flags, false);
+        InstallParams ip = sampleInstallFromRawResource(flags, false);
         boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
         GenericReceiver receiver;
         if (replace) {
@@ -409,7 +449,7 @@
 
     @MediumTest
     public void testReplaceFailSdcard() {
-        replaceFromRawResource(PackageManager.INSTALL_ON_SDCARD);
+        replaceFromRawResource(PackageManager.INSTALL_EXTERNAL);
     }
 
     @MediumTest
@@ -426,7 +466,7 @@
     @MediumTest
     public void testReplaceSdcard() {
         replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
-                PackageManager.INSTALL_ON_SDCARD);
+                PackageManager.INSTALL_EXTERNAL);
     }
 
     /* -------------- Delete tests ---*/
@@ -508,7 +548,7 @@
     }
 
     public void deleteFromRawResource(int iFlags, int dFlags) {
-        InstallParams ip = installFromRawResource(iFlags, false);
+        InstallParams ip = sampleInstallFromRawResource(iFlags, false);
         boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0);
         GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
         DeleteObserver observer = new DeleteObserver();
@@ -550,7 +590,7 @@
 
     @MediumTest
     public void testDeleteSdcard() {
-        deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, 0);
+        deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, 0);
     }
 
     @MediumTest
@@ -565,7 +605,7 @@
 
     @MediumTest
     public void testDeleteSdcardRetainData() {
-        deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, PackageManager.DONT_DELETE_DATA);
+        deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DONT_DELETE_DATA);
     }
 
     /* sdcard mount/unmount tests ******/
@@ -696,7 +736,7 @@
 
     private boolean mountFromRawResource() {
         // Install pkg on sdcard
-        InstallParams ip = installFromRawResource(PackageManager.INSTALL_ON_SDCARD |
+        InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL |
                 PackageManager.INSTALL_REPLACE_EXISTING, false);
         if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
         boolean origState = getMediaState();
@@ -764,169 +804,32 @@
         }
     }
 
-    public void invokeRecommendAppInstallLocation(String outFileName,
-            int fileResId, int expected) {
-        int origSetting = Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 0);
-        try {
-            // Make sure the set install location setting is diabled.
-            Settings.System.putInt(mContext.getContentResolver(),
-                    Settings.System.SET_INSTALL_LOCATION, 0);
-            File filesDir = mContext.getFilesDir();
-            File outFile = new File(filesDir, outFileName);
-            Uri packageURI = getInstallablePackage(fileResId, outFile);
-            PackageParser.Package pkg = parsePackage(packageURI);
-            assertNotNull(pkg);
-            int installLoc = getPm().recommendAppInstallLocation(pkg);
-            Log.i(TAG, "expected=" + expected +", installLoc="+installLoc);
-            // Atleast one of the specified expected flags should be set.
-            boolean onFlash = (installLoc &
-                    PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
-            boolean onSd = (installLoc &
-                    PackageManager.INSTALL_ON_SDCARD) != 0;
-            boolean expOnFlash = (expected &
-                    PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
-            boolean expOnSd = (expected &
-                    PackageManager.INSTALL_ON_SDCARD) != 0;
-            assertTrue(expOnFlash == onFlash || expOnSd == onSd);
-        } finally {
-            // Restore original setting
-            Settings.System.putInt(mContext.getContentResolver(),
-                    Settings.System.SET_INSTALL_LOCATION, origSetting);
-        }
+    public void testManifestInstallLocationInternal() {
+        installFromRawResource("install.apk", R.raw.install_loc_internal,
+                0, true, false, -1);
     }
 
-    /*
-     * Tests if an apk can be installed on internal flash by
-     * explicitly specifying in its manifest.
-     */
-    public void testInstallLocationInternal() {
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_internal, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    public void testManifestInstallLocationSdcard() {
+        installFromRawResource("install.apk", R.raw.install_loc_sdcard,
+                PackageManager.INSTALL_EXTERNAL, true, false, -1);
     }
 
-    /*
-     * Tests if an apk can be installed on internal flash by
-     * explicitly specifying in its manifest and filling up
-     * internal flash. Should fail to install.
-     * TODO
-     */
-    public void xxxtestInstallLocationInternalFail() {
+    public void testManifestInstallLocationAuto() {
+        installFromRawResource("install.apk", R.raw.install_loc_auto,
+                0, true, false, -1);
     }
 
-    /*
-     * Tests if an apk can be installed on sdcard by
-     * explicitly specifying in its manifest.
-     */
-    public void testInstallLocationSdcard() {
-        // TODO No guarantee this will be on sdcard.
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_sdcard, PackageManager.INSTALL_ON_SDCARD
-                | PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    public void testManifestInstallLocationUnspecified() {
+        installFromRawResource("install.apk", R.raw.install_loc_unspecified,
+                0, true, false, -1);
     }
 
-    /*
-     * Tests if an apk can be installed on sdcard by
-     * explicitly specifying in its manifest and filling up
-     * the sdcard. Should result in install failure
-     * TODO
-     */
-    public void xxxtestInstallLocationSdcardFail() {
+    public void testManifestInstallLocationFwdLockedSdcard() {
+        installFromRawResource("install.apk", R.raw.install_loc_sdcard,
+                PackageManager.INSTALL_FORWARD_LOCK |
+                PackageManager.INSTALL_EXTERNAL, true, true,
+                PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION);
     }
-
-    /*
-     * Tests if an apk can be installed by specifying
-     * auto for install location
-     */
-    public void xxxtestInstallLocationAutoInternal() {
-        // TODO clear and make room on internal flash
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_auto, PackageManager.INSTALL_ON_INTERNAL_FLASH);
-    }
-
-    /*
-     * Tests if an apk can be installed by specifying
-     * auto for install location
-     */
-    public void testInstallLocationAutoSdcard() {
-        // TODO clear and make room on sdcard.
-        // Fill up internal
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_auto, PackageManager.INSTALL_ON_SDCARD |
-                PackageManager.INSTALL_ON_INTERNAL_FLASH);
-    }
-
-    /*
-     * Tests if an apk can be installed by specifying
-     * auto for install location
-     * fill up both internal and sdcard
-     * TODO
-     */
-    public void xxxtestInstallLocationAutoFail() {
-    }
-    /*
-     * Tests where an apk gets installed based
-     * on a not specifying anything in manifest.
-     */
-    public void testInstallLocationUnspecifiedInt() {
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
-    }
-
-    public void xxxtestInstallLocationUnspecifiedStorage() {
-        // TODO Fill up internal storage
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD
-                | PackageManager.INSTALL_ON_INTERNAL_FLASH);
-    }
-
-    /*
-     * Tests where an apk gets installed by expcitly setting
-     * the user specified install location
-     */
-    public void testInstallLocationUserSpecifiedInternal() {
-        // Enable user setting
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 1);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.DEFAULT_INSTALL_LOCATION, 1);
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
-    }
-
-    /*
-     * Tests where an apk gets installed by expcitly setting
-     * the user specified install location
-     */
-    public void testInstallLocationUserSpecifiedSdcard() {
-        // Enable user setting
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 1);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.DEFAULT_INSTALL_LOCATION, 2);
-        int i = Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.DEFAULT_INSTALL_LOCATION, 0);
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 0);
-    }
-    /*
-     * Tests where an apk gets installed by expcitly setting
-     * the user specified install location
-     */
-    public void testInstallLocationUserSpecifiedAuto() {
-        // Enable user setting
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 1);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.DEFAULT_INSTALL_LOCATION, 0);
-        invokeRecommendAppInstallLocation("install.apk",
-                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SET_INSTALL_LOCATION, 0);
-    }
-
     /*
      * TODO's
      * check version numbers for upgrades