Merge "Enable onepointfivetap-and-swipe to select."
diff --git a/api/current.xml b/api/current.xml
index ad5a1a7..b8621d8 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -595,6 +595,17 @@
  visibility="public"
 >
 </field>
+<field name="KILL_BACKGROUND_PROCESSES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.KILL_BACKGROUND_PROCESSES&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MANAGE_ACCOUNTS"
  type="java.lang.String"
  transient="false"
@@ -899,7 +910,7 @@
  value="&quot;android.permission.RESTART_PACKAGES&quot;"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -17534,7 +17545,7 @@
 <exception name="SecurityException" type="java.lang.SecurityException">
 </exception>
 </method>
-<method name="restartPackage"
+<method name="killBackgroundProcesses"
  return="void"
  abstract="false"
  native="false"
@@ -17547,6 +17558,19 @@
 <parameter name="packageName" type="java.lang.String">
 </parameter>
 </method>
+<method name="restartPackage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
 <field name="RECENT_WITH_EXCLUDED"
  type="int"
  transient="false"
@@ -74858,6 +74882,75 @@
 </exception>
 </method>
 </class>
+<class name="GeocoderParams"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getClientPackage"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocale"
+ return="java.util.Locale"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="GpsSatellite"
  extends="java.lang.Object"
  abstract="false"
@@ -76157,6 +76250,62 @@
 >
 </field>
 </class>
+<interface name="LocationManager.GeocodeProvider"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getFromLocation"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="latitude" type="double">
+</parameter>
+<parameter name="longitude" type="double">
+</parameter>
+<parameter name="maxResults" type="int">
+</parameter>
+<parameter name="params" type="android.location.GeocoderParams">
+</parameter>
+<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
+</parameter>
+</method>
+<method name="getFromLocationName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="locationName" type="java.lang.String">
+</parameter>
+<parameter name="lowerLeftLatitude" type="double">
+</parameter>
+<parameter name="lowerLeftLongitude" type="double">
+</parameter>
+<parameter name="upperRightLatitude" type="double">
+</parameter>
+<parameter name="upperRightLongitude" type="double">
+</parameter>
+<parameter name="maxResults" type="int">
+</parameter>
+<parameter name="params" type="android.location.GeocoderParams">
+</parameter>
+<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
+</parameter>
+</method>
+</interface>
 <class name="LocationProvider"
  extends="java.lang.Object"
  abstract="true"
@@ -126572,6 +126721,17 @@
  visibility="public"
 >
 </field>
+<field name="UNKNOWN_STRING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;&lt;unknown&gt;&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="MediaStore.Audio"
  extends="java.lang.Object"
@@ -127056,6 +127216,17 @@
  visibility="public"
 >
 </field>
+<field name="BOOKMARK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;bookmark&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="COMPOSER"
  type="java.lang.String"
  transient="false"
@@ -127111,6 +127282,17 @@
  visibility="public"
 >
 </field>
+<field name="IS_PODCAST"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;is_podcast&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="IS_RINGTONE"
  type="java.lang.String"
  transient="false"
@@ -127569,6 +127751,25 @@
 <parameter name="playlistId" type="long">
 </parameter>
 </method>
+<method name="moveItem"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.ContentResolver">
+</parameter>
+<parameter name="playlistId" type="long">
+</parameter>
+<parameter name="from" type="int">
+</parameter>
+<parameter name="to" type="int">
+</parameter>
+</method>
 <field name="AUDIO_ID"
  type="java.lang.String"
  transient="false"
@@ -199666,6 +199867,23 @@
 <parameter name="value" type="boolean">
 </parameter>
 </method>
+<method name="setBundle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="setByte"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7d07604..930ab65 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -891,6 +891,38 @@
     }
     
     /**
+     * @deprecated This is now just a wrapper for
+     * {@link #killBackgroundProcesses(String)}; the previous behavior here
+     * is no longer available to applications because it allows them to
+     * break other applications by removing their alarms, stopping their
+     * services, etc.
+     */
+    @Deprecated
+    public void restartPackage(String packageName) {
+        killBackgroundProcesses(packageName);
+    }
+    
+    /**
+     * Have the system immediately kill all background processes associated
+     * with the given package.  This is the same as the kernel killing those
+     * processes to reclaim memory; the system will take care of restarting
+     * these processes in the future as needed.
+     * 
+     * <p>You must hold the permission
+     * {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to
+     * call this method.
+     * 
+     * @param packageName The name of the package whose processes are to
+     * be killed.
+     */
+    public void killBackgroundProcesses(String packageName) {
+        try {
+            ActivityManagerNative.getDefault().killBackgroundProcesses(packageName);
+        } catch (RemoteException e) {
+        }
+    }
+    
+    /**
      * Have the system perform a force stop of everything associated with
      * the given application package.  All processes that share its uid
      * will be killed, all services it has running stopped, all activities
@@ -899,14 +931,18 @@
      * be stopped, notifications removed, etc.
      * 
      * <p>You must hold the permission
-     * {@link android.Manifest.permission#RESTART_PACKAGES} to be able to
+     * {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to
      * call this method.
      * 
      * @param packageName The name of the package to be stopped.
+     * 
+     * @hide This is not available to third party applications due to
+     * it allowing them to break other applications by stopping their
+     * services, removing their alarms, etc.
      */
-    public void restartPackage(String packageName) {
+    public void forceStopPackage(String packageName) {
         try {
-            ActivityManagerNative.getDefault().restartPackage(packageName);
+            ActivityManagerNative.getDefault().forceStopPackage(packageName);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 90f46dd..09b88ee 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1007,10 +1007,18 @@
             return true;
         }
 
-        case RESTART_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);            
+        case KILL_BACKGROUND_PROCESSES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
             String packageName = data.readString();
-            restartPackage(packageName);
+            killBackgroundProcesses(packageName);
+            reply.writeNoException();
+            return true;
+        }
+        
+        case FORCE_STOP_PACKAGE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String packageName = data.readString();
+            forceStopPackage(packageName);
             reply.writeNoException();
             return true;
         }
@@ -2388,12 +2396,23 @@
         reply.recycle();
     }
     
-    public void restartPackage(String packageName) throws RemoteException {
+    public void killBackgroundProcesses(String packageName) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
-        mRemote.transact(RESTART_PACKAGE_TRANSACTION, data, reply, 0);
+        mRemote.transact(KILL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    
+    public void forceStopPackage(String packageName) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        mRemote.transact(FORCE_STOP_PACKAGE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ca6bfa7..016d465 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -216,7 +216,8 @@
     
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
     
-    public void restartPackage(final String packageName) throws RemoteException;
+    public void killBackgroundProcesses(final String packageName) throws RemoteException;
+    public void forceStopPackage(final String packageName) throws RemoteException;
     
     // Note: probably don't want to allow applications access to these.
     public void goingToSleep() throws RemoteException;
@@ -424,7 +425,7 @@
     int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+75;
     int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
     int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
-    int RESTART_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
+    int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
     int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
     int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
@@ -448,4 +449,5 @@
     int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
     int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
     int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
+    int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
 }
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 76131fc..b0c3909 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1118,6 +1118,11 @@
         if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear();
         mSwipeTracker.addMovement(me);
 
+        // Ignore all motion events until a DOWN.
+        if (mAbortKey && action != MotionEvent.ACTION_DOWN) {
+            return true;
+        }
+
         if (mGestureDetector.onTouchEvent(me)) {
             showPreview(NOT_A_KEY);
             mHandler.removeMessages(MSG_REPEAT);
@@ -1150,9 +1155,14 @@
                         mKeys[keyIndex].codes[0] : 0);
                 if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) {
                     mRepeatKeyIndex = mCurrentKey;
-                    repeatKey();
                     Message msg = mHandler.obtainMessage(MSG_REPEAT);
                     mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY);
+                    repeatKey();
+                    // Delivering the key could have caused an abort
+                    if (mAbortKey) {
+                        mRepeatKeyIndex = NOT_A_KEY;
+                        break;
+                    }
                 }
                 if (mCurrentKey != NOT_A_KEY) {
                     Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me);
diff --git a/core/java/android/net/http/DomainNameChecker.java b/core/java/android/net/http/DomainNameChecker.java
index e4c8009..3e01d2c 100644
--- a/core/java/android/net/http/DomainNameChecker.java
+++ b/core/java/android/net/http/DomainNameChecker.java
@@ -231,7 +231,7 @@
                     rval = thisDomainTokens[i].equals(thatDomainTokens[i]);
                     if (!rval) {
                         // (c) OR we have a special *-match:
-                        // Z.Y.X matches *.Y.X but does not match *.X
+                        // *.Y.X matches Z.Y.X but *.X doesn't match Z.Y.X
                         rval = (i == 0 && thisDomainTokensNum == thatDomainTokensNum);
                         if (rval) {
                             rval = thatDomainTokens[0].equals("*");
@@ -242,10 +242,13 @@
                                     thisDomainTokens[0], thatDomainTokens[0]);
                             }
                         }
-
                         break;
                     }
                 }
+            } else {
+              // (e) OR thatHost has a '*.'-prefix of thisHost:
+              // *.Y.X matches Y.X
+              rval = thatDomain.equals("*." + thisDomain);
             }
         }
 
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
new file mode 100644
index 0000000..130cfef
--- /dev/null
+++ b/core/java/android/os/RecoverySystem.java
@@ -0,0 +1,420 @@
+/*
+ * 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.os;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+import org.apache.harmony.security.pkcs7.SignedData;
+import org.apache.harmony.security.pkcs7.SignerInfo;
+import org.apache.harmony.security.provider.cert.X509CertImpl;
+
+/**
+ * RecoverySystem contains methods for interacting with the Android
+ * recovery system (the separate partition that can be used to install
+ * system updates, wipe user data, etc.)
+ *
+ * @pending
+ */
+public class RecoverySystem {
+    private static final String TAG = "RecoverySystem";
+
+    /**
+     * Default location of zip file containing public keys (X509
+     * certs) authorized to sign OTA updates.
+     */
+    private static final File DEFAULT_KEYSTORE =
+        new File("/system/etc/security/otacerts.zip");
+
+    /** Send progress to listeners no more often than this (in ms). */
+    private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
+
+    /** Used to communicate with recovery.  See bootable/recovery/recovery.c. */
+    private static File RECOVERY_DIR = new File("/cache/recovery");
+    private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
+    private static File LOG_FILE = new File(RECOVERY_DIR, "log");
+
+    // Length limits for reading files.
+    private static int LOG_FILE_MAX_LENGTH = 8 * 1024;
+
+    /**
+     * Interface definition for a callback to be invoked regularly as
+     * verification proceeds.
+     */
+    public interface ProgressListener {
+        /**
+         * Called periodically as the verification progresses.
+         *
+         * @param progress  the approximate percentage of the
+         *        verification that has been completed, ranging from 0
+         *        to 100 (inclusive).
+         */
+        public void onProgress(int progress);
+    }
+
+    /** @return the set of certs that can be used to sign an OTA package. */
+    private static HashSet<Certificate> getTrustedCerts(File keystore)
+        throws IOException, GeneralSecurityException {
+        HashSet<Certificate> trusted = new HashSet<Certificate>();
+        if (keystore == null) {
+            keystore = DEFAULT_KEYSTORE;
+        }
+        ZipFile zip = new ZipFile(keystore);
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            Enumeration<? extends ZipEntry> entries = zip.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = entries.nextElement();
+                trusted.add(cf.generateCertificate(zip.getInputStream(entry)));
+            }
+        } finally {
+            zip.close();
+        }
+        return trusted;
+    }
+
+    /**
+     * Verify the cryptographic signature of a system update package
+     * before installing it.  Note that the package is also verified
+     * separately by the installer once the device is rebooted into
+     * the recovery system.  This function will return only if the
+     * package was successfully verified; otherwise it will throw an
+     * exception.
+     *
+     * Verification of a package can take significant time, so this
+     * function should not be called from a UI thread.
+     *
+     * @param packageFile  the package to be verified
+     * @param listener     an object to receive periodic progress
+     * updates as verification proceeds.  May be null.
+     * @param deviceCertsZipFile  the zip file of certificates whose
+     * public keys we will accept.  Verification succeeds if the
+     * package is signed by the private key corresponding to any
+     * public key in this file.  May be null to use the system default
+     * file (currently "/system/etc/security/otacerts.zip").
+     *
+     * @throws IOException if there were any errors reading the
+     * package or certs files.
+     * @throws GeneralSecurityException if verification failed
+     */
+    public static void verifyPackage(File packageFile,
+                                     ProgressListener listener,
+                                     File deviceCertsZipFile)
+        throws IOException, GeneralSecurityException {
+        long fileLen = packageFile.length();
+
+        RandomAccessFile raf = new RandomAccessFile(packageFile, "r");
+        try {
+            int lastPercent = 0;
+            long lastPublishTime = System.currentTimeMillis();
+            if (listener != null) {
+                listener.onProgress(lastPercent);
+            }
+
+            raf.seek(fileLen - 6);
+            byte[] footer = new byte[6];
+            raf.readFully(footer);
+
+            if (footer[2] != (byte)0xff || footer[3] != (byte)0xff) {
+                throw new SignatureException("no signature in file (no footer)");
+            }
+
+            int commentSize = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8);
+            int signatureStart = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8);
+            Log.v(TAG, String.format("comment size %d; signature start %d",
+                                     commentSize, signatureStart));
+
+            byte[] eocd = new byte[commentSize + 22];
+            raf.seek(fileLen - (commentSize + 22));
+            raf.readFully(eocd);
+
+            // Check that we have found the start of the
+            // end-of-central-directory record.
+            if (eocd[0] != (byte)0x50 || eocd[1] != (byte)0x4b ||
+                eocd[2] != (byte)0x05 || eocd[3] != (byte)0x06) {
+                throw new SignatureException("no signature in file (bad footer)");
+            }
+
+            for (int i = 4; i < eocd.length-3; ++i) {
+                if (eocd[i  ] == (byte)0x50 && eocd[i+1] == (byte)0x4b &&
+                    eocd[i+2] == (byte)0x05 && eocd[i+3] == (byte)0x06) {
+                    throw new SignatureException("EOCD marker found after start of EOCD");
+                }
+            }
+
+            // The following code is largely copied from
+            // JarUtils.verifySignature().  We could just *call* that
+            // method here if that function didn't read the entire
+            // input (ie, the whole OTA package) into memory just to
+            // compute its message digest.
+
+            BerInputStream bis = new BerInputStream(
+                new ByteArrayInputStream(eocd, commentSize+22-signatureStart, signatureStart));
+            ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);
+            SignedData signedData = info.getSignedData();
+            if (signedData == null) {
+                throw new IOException("signedData is null");
+            }
+            Collection encCerts = signedData.getCertificates();
+            if (encCerts.isEmpty()) {
+                throw new IOException("encCerts is empty");
+            }
+            // Take the first certificate from the signature (packages
+            // should contain only one).
+            Iterator it = encCerts.iterator();
+            X509Certificate cert = null;
+            if (it.hasNext()) {
+                cert = new X509CertImpl((org.apache.harmony.security.x509.Certificate)it.next());
+            } else {
+                throw new SignatureException("signature contains no certificates");
+            }
+
+            List sigInfos = signedData.getSignerInfos();
+            SignerInfo sigInfo;
+            if (!sigInfos.isEmpty()) {
+                sigInfo = (SignerInfo)sigInfos.get(0);
+            } else {
+                throw new IOException("no signer infos!");
+            }
+
+            // Check that the public key of the certificate contained
+            // in the package equals one of our trusted public keys.
+
+            HashSet<Certificate> trusted = getTrustedCerts(
+                deviceCertsZipFile == null ? DEFAULT_KEYSTORE : deviceCertsZipFile);
+
+            PublicKey signatureKey = cert.getPublicKey();
+            boolean verified = false;
+            for (Certificate c : trusted) {
+                if (c.getPublicKey().equals(signatureKey)) {
+                    verified = true;
+                    break;
+                }
+            }
+            if (!verified) {
+                throw new SignatureException("signature doesn't match any trusted key");
+            }
+
+            // The signature cert matches a trusted key.  Now verify that
+            // the digest in the cert matches the actual file data.
+
+            // The verifier in recovery *only* handles SHA1withRSA
+            // signatures.  SignApk.java always uses SHA1withRSA, no
+            // matter what the cert says to use.  Ignore
+            // cert.getSigAlgName(), and instead use whatever
+            // algorithm is used by the signature (which should be
+            // SHA1withRSA).
+
+            String da = sigInfo.getdigestAlgorithm();
+            String dea = sigInfo.getDigestEncryptionAlgorithm();
+            String alg = null;
+            if (da == null || dea == null) {
+                // fall back to the cert algorithm if the sig one
+                // doesn't look right.
+                alg = cert.getSigAlgName();
+            } else {
+                alg = da + "with" + dea;
+            }
+            Signature sig = Signature.getInstance(alg);
+            sig.initVerify(cert);
+
+            // The signature covers all of the OTA package except the
+            // archive comment and its 2-byte length.
+            long toRead = fileLen - commentSize - 2;
+            long soFar = 0;
+            raf.seek(0);
+            byte[] buffer = new byte[4096];
+            while (soFar < toRead) {
+                int size = buffer.length;
+                if (soFar + size > toRead) {
+                    size = (int)(toRead - soFar);
+                }
+                int read = raf.read(buffer, 0, size);
+                sig.update(buffer, 0, read);
+                soFar += read;
+
+                if (listener != null) {
+                    long now = System.currentTimeMillis();
+                    int p = (int)(soFar * 100 / toRead);
+                    if (p > lastPercent &&
+                        now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {
+                        lastPercent = p;
+                        lastPublishTime = now;
+                        listener.onProgress(lastPercent);
+                    }
+                }
+            }
+            if (listener != null) {
+                listener.onProgress(100);
+            }
+
+            if (!sig.verify(sigInfo.getEncryptedDigest())) {
+                throw new SignatureException("signature digest verification failed");
+            }
+        } finally {
+            raf.close();
+        }
+    }
+
+    /**
+     * Reboots the device in order to install the given update
+     * package.
+     * Requires the {@link android.Manifest.permission#REBOOT}
+     * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
+     * permissions.
+     *
+     * @param context      the Context to use
+     * @param packageFile  the update package to install.  Currently
+     * must be on the /cache or /data partitions.
+     *
+     * @throws IOException  if writing the recovery command file
+     * fails, or if the reboot itself fails.
+     */
+    public static void installPackage(Context context, File packageFile)
+        throws IOException {
+        String filename = packageFile.getCanonicalPath();
+
+        if (filename.startsWith("/cache/")) {
+            filename = "CACHE:" + filename.substring(7);
+        } else if (filename.startsWith("/data/")) {
+            filename = "DATA:" + filename.substring(6);
+        } else {
+            throw new IllegalArgumentException(
+                "Must start with /cache or /data: " + filename);
+        }
+        Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+        String arg = "--update_package=" + filename;
+        bootCommand(context, arg);
+    }
+
+    /**
+     * Reboots the device and wipes the user data partition.  This is
+     * sometimes called a "factory reset", which is something of a
+     * misnomer because the system partition is not restored to its
+     * factory state.
+     * Requires the {@link android.Manifest.permission#REBOOT}
+     * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
+     * permissions.
+     *
+     * @param context  the Context to use
+     *
+     * @throws IOException  if writing the recovery command file
+     * fails, or if the reboot itself fails.
+     */
+    public static void rebootWipeUserData(Context context)
+        throws IOException {
+        bootCommand(context, "--wipe_data");
+    }
+
+    /**
+     * Reboot into the recovery system to wipe the /data partition and toggle
+     * Encrypted File Systems on/off.
+     * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
+     * @throws IOException if something goes wrong.
+     *
+     * @hide
+     */
+    public static void rebootToggleEFS(Context context, boolean efsEnabled)
+        throws IOException {
+        if (efsEnabled) {
+            bootCommand(context, "--set_encrypted_filesystem=on");
+        } else {
+            bootCommand(context, "--set_encrypted_filesystem=off");
+        }
+    }
+
+    /**
+     * Reboot into the recovery system with the supplied argument.
+     * @param arg to pass to the recovery utility.
+     * @throws IOException if something goes wrong.
+     */
+    private static void bootCommand(Context context, String arg) throws IOException {
+        RECOVERY_DIR.mkdirs();  // In case we need it
+        COMMAND_FILE.delete();  // In case it's not writable
+        LOG_FILE.delete();
+
+        FileWriter command = new FileWriter(COMMAND_FILE);
+        try {
+            command.write(arg);
+            command.write("\n");
+        } finally {
+            command.close();
+        }
+
+        // Having written the command file, go ahead and reboot
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        pm.reboot("recovery");
+
+        throw new IOException("Reboot failed (no permissions?)");
+    }
+
+    /**
+     * Called after booting to process and remove recovery-related files.
+     * @return the log file from recovery, or null if none was found.
+     *
+     * @hide
+     */
+    public static String handleAftermath() {
+        // Record the tail of the LOG_FILE
+        String log = null;
+        try {
+            log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
+        } catch (FileNotFoundException e) {
+            Log.i(TAG, "No recovery log file");
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading recovery log", e);
+        }
+
+        // Delete everything in RECOVERY_DIR
+        String[] names = RECOVERY_DIR.list();
+        for (int i = 0; names != null && i < names.length; i++) {
+            File f = new File(RECOVERY_DIR, names[i]);
+            if (!f.delete()) {
+                Log.e(TAG, "Can't delete: " + f);
+            } else {
+                Log.i(TAG, "Deleted: " + f);
+            }
+        }
+
+        return log;
+    }
+
+    private void RecoverySystem() { }  // Do not instantiate
+}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 1d06f90..6d1fef6 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -182,7 +182,6 @@
       * The string that is used when a media attribute is not known. For example,
       * if an audio file does not have any meta data, the artist and album columns
       * will be set to this value.
-      * @hide
       */
     public static final String UNKNOWN_STRING = "<unknown>";
 
@@ -852,7 +851,6 @@
              * The position, in ms, playback was at when playback for this file
              * was last stopped.
              * <P>Type: INTEGER (long)</P>
-             * @hide
              */
             public static final String BOOKMARK = "bookmark";
 
@@ -931,7 +929,6 @@
             /**
              * Non-zero if the audio file is a podcast
              * <P>Type: INTEGER (boolean)</P>
-             * @hide
              */
             public static final String IS_PODCAST = "is_podcast";
 
@@ -1266,7 +1263,6 @@
                  * @param from The position of the item to move
                  * @param to The position to move the item to
                  * @return true on success
-                 * @hide
                  */
                 public static final boolean moveItem(ContentResolver res,
                         long playlistId, int from, int to) {
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 81dd96e..ce0b954 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,134 +16,43 @@
 
 package android.util;
 
-import com.google.android.collect.Lists;
-
+import java.io.BufferedReader;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
- * {@hide}
- * Dynamically defined (in terms of event types), space efficient (i.e. "tight") event logging
- * to help instrument code for large scale stability and performance monitoring.
+ * Access to the system diagnostic event record.  System diagnostic events are
+ * used to record certain system-level events (such as garbage collection,
+ * activity manager state, system watchdogs, and other low level activity),
+ * which may be automatically collected and analyzed during system development.
  *
- * Note that this class contains all static methods.  This is done for efficiency reasons.
+ * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
+ * These diagnostic events are for system integrators, not application authors.
  *
- * Events for the event log are self-describing binary data structures.  They start with a 20 byte
- * header (generated automatically) which contains all of the following in order:
+ * <p>Events use integer tag codes corresponding to /system/etc/event-log-tags.
+ * They carry a payload of one or more int, long, or String values.  The
+ * event-log-tags file defines the payload contents for each type code.
  *
- * <ul>
- * <li> Payload length: 2 bytes - length of the non-header portion </li>
- * <li> Padding: 2 bytes - no meaning at this time </li>
- * <li> Timestamp:
- *   <ul>
- *   <li> Seconds: 4 bytes - seconds since Epoch </li>
- *   <li> Nanoseconds: 4 bytes - plus extra nanoseconds </li>
- *   </ul></li>
- * <li> Process ID: 4 bytes - matching {@link android.os.Process#myPid} </li>
- * <li> Thread ID: 4 bytes - matching {@link android.os.Process#myTid} </li>
- * </li>
- * </ul>
- *
- * The above is followed by a payload, comprised of the following:
- * <ul>
- * <li> Tag: 4 bytes - unique integer used to identify a particular event.  This number is also
- *                     used as a key to map to a string that can be displayed by log reading tools.
- * </li>
- * <li> Type: 1 byte - can be either {@link #INT}, {@link #LONG}, {@link #STRING},
- *                     or {@link #LIST}. </li>
- * <li> Event log value: the size and format of which is one of:
- *   <ul>
- *   <li> INT: 4 bytes </li>
- *   <li> LONG: 8 bytes </li>
- *   <li> STRING:
- *     <ul>
- *     <li> Size of STRING: 4 bytes </li>
- *     <li> The string:  n bytes as specified in the size fields above. </li>
- *     </ul></li>
- *   <li> {@link List LIST}:
- *     <ul>
- *     <li> Num items: 1 byte </li>
- *     <li> N value payloads, where N is the number of items specified above. </li>
- *     </ul></li>
- *   </ul>
- * </li>
- * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- *                     corruption and enable standard unix tools like grep, tail and wc to operate
- *                     on event logs. </li>
- * </ul>
- *
- * Note that all output is done in the endian-ness of the device (as determined
- * by {@link ByteOrder#nativeOrder()}).
+ * @pending
  */
-
 public class EventLog {
+    private static final String TAG = "EventLog";
 
-    // Value types
-    public static final byte INT    = 0;
-    public static final byte LONG   = 1;
-    public static final byte STRING = 2;
-    public static final byte LIST   = 3;
+    private static final String TAGS_FILE = "/system/etc/event-log-tags";
+    private static final String COMMENT_PATTERN = "^\\s*(#.*)?$";
+    private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$";
+    private static HashMap<String, Integer> sTagCodes = null;
+    private static HashMap<Integer, String> sTagNames = null;
 
-    /**
-     * An immutable tuple used to log a heterogeneous set of loggable items.
-     * The items can be Integer, Long, String, or {@link List}.
-     * The maximum number of items is 127
-     */
-    public static final class List {
-        private Object[] mItems;
-
-        /**
-         * Get a particular tuple item
-         * @param pos The position of the item in the tuple
-         */
-        public final Object getItem(int pos) {
-            return mItems[pos];
-        }
-
-        /**
-         * Get the number of items in the tuple.
-         */
-        public final byte getNumItems() {
-            return (byte) mItems.length;
-        }
-
-        /**
-         * Create a new tuple.
-         * @param items The items to create the tuple with, as varargs.
-         * @throws IllegalArgumentException if the arguments are too few (0),
-         *         too many, or aren't loggable types.
-         */
-        public List(Object... items) throws IllegalArgumentException {
-            if (items.length > Byte.MAX_VALUE) {
-                throw new IllegalArgumentException(
-                        "A List must have fewer than "
-                        + Byte.MAX_VALUE + " items in it.");
-            }
-            for (int i = 0; i < items.length; i++) {
-                final Object item = items[i];
-                if (item == null) {
-                    // Would be nice to be able to write null strings...
-                    items[i] = "";
-                } else if (!(item instanceof List ||
-                      item instanceof String ||
-                      item instanceof Integer ||
-                      item instanceof Long)) {
-                    throw new IllegalArgumentException(
-                            "Attempt to create a List with illegal item type.");
-                }
-            }
-            this.mItems = items;
-        }
-    }
-
-    /**
-     * A previously logged event read from the logs.
-     */
+    /** A previously logged event read from the logs. */
     public static final class Event {
         private final ByteBuffer mBuffer;
 
@@ -158,77 +67,83 @@
         private static final int TAG_OFFSET = 20;
         private static final int DATA_START = 24;
 
+        // Value types
+        private static final byte INT_TYPE    = 0;
+        private static final byte LONG_TYPE   = 1;
+        private static final byte STRING_TYPE = 2;
+        private static final byte LIST_TYPE   = 3;
+
         /** @param data containing event, read from the system */
-        public Event(byte[] data) {
+        /*package*/ Event(byte[] data) {
             mBuffer = ByteBuffer.wrap(data);
             mBuffer.order(ByteOrder.nativeOrder());
         }
 
+        /** @return the process ID which wrote the log entry */
         public int getProcessId() {
             return mBuffer.getInt(PROCESS_OFFSET);
         }
 
+        /** @return the thread ID which wrote the log entry */
         public int getThreadId() {
             return mBuffer.getInt(THREAD_OFFSET);
         }
 
+        /** @return the wall clock time when the entry was written */
         public long getTimeNanos() {
             return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l
                     + mBuffer.getInt(NANOSECONDS_OFFSET);
         }
 
+        /** @return the type tag code of the entry */
         public int getTag() {
             return mBuffer.getInt(TAG_OFFSET);
         }
 
-        /** @return one of Integer, Long, String, or List. */
+        /** @return one of Integer, Long, String, null, or Object[] of same. */
         public synchronized Object getData() {
-            mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
-            mBuffer.position(DATA_START);  // Just after the tag.
-            return decodeObject();
-        }
-
-        public byte[] getRawData() {
-            return mBuffer.array();
+            try {
+                mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
+                mBuffer.position(DATA_START);  // Just after the tag.
+                return decodeObject();
+            } catch (IllegalArgumentException e) {
+                Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
+                return null;
+            } catch (BufferUnderflowException e) {
+                Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e);
+                return null;
+            }
         }
 
         /** @return the loggable item at the current position in mBuffer. */
         private Object decodeObject() {
-            if (mBuffer.remaining() < 1) return null;
-            switch (mBuffer.get()) {
-            case INT:
-                if (mBuffer.remaining() < 4) return null;
+            byte type = mBuffer.get();
+            switch (type) {
+            case INT_TYPE:
                 return (Integer) mBuffer.getInt();
 
-            case LONG:
-                if (mBuffer.remaining() < 8) return null;
+            case LONG_TYPE:
                 return (Long) mBuffer.getLong();
 
-            case STRING:
+            case STRING_TYPE:
                 try {
-                    if (mBuffer.remaining() < 4) return null;
                     int length = mBuffer.getInt();
-                    if (length < 0 || mBuffer.remaining() < length) return null;
                     int start = mBuffer.position();
                     mBuffer.position(start + length);
                     return new String(mBuffer.array(), start, length, "UTF-8");
                 } catch (UnsupportedEncodingException e) {
-                    throw new RuntimeException(e);  // UTF-8 is guaranteed.
+                    Log.wtf(TAG, "UTF-8 is not supported", e);
+                    return null;
                 }
 
-            case LIST:
-                if (mBuffer.remaining() < 1) return null;
+            case LIST_TYPE:
                 int length = mBuffer.get();
-                if (length < 0) return null;
                 Object[] array = new Object[length];
-                for (int i = 0; i < length; ++i) {
-                    array[i] = decodeObject();
-                    if (array[i] == null) return null;
-                }
-                return new List(array);
+                for (int i = 0; i < length; ++i) array[i] = decodeObject();
+                return array;
 
             default:
-                return null;
+                throw new IllegalArgumentException("Unknown entry type: " + type);
             }
         }
     }
@@ -236,46 +151,36 @@
     // We assume that the native methods deal with any concurrency issues.
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param value A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, int value);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param value A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, long value);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param str A value to log
      * @return The number of bytes written
      */
     public static native int writeEvent(int tag, String str);
 
     /**
-     * Send an event log message.
-     * @param tag An event identifer
-     * @param list A {@link List} to log
-     * @return The number of bytes written
-     */
-    public static native int writeEvent(int tag, List list);
-
-    /**
-     * Send an event log message.
-     * @param tag An event identifer
+     * Record an event log message.
+     * @param tag The event type tag code
      * @param list A list of values to log
      * @return The number of bytes written
      */
-    public static int writeEvent(int tag, Object... list) {
-        return writeEvent(tag, new List(list));
-    }
+    public static native int writeEvent(int tag, Object... list);
 
     /**
      * Read events from the log, filtered by type.
@@ -287,11 +192,65 @@
             throws IOException;
 
     /**
-     * Read events from a file.
-     * @param path to read from
-     * @param output container to add events into
-     * @throws IOException if something goes wrong reading events
+     * Get the name associated with an event type tag code.
+     * @param tag code to look up
+     * @return the name of the tag, or null if no tag has that number
      */
-    public static native void readEvents(String path, Collection<Event> output)
-            throws IOException;
+    public static String getTagName(int tag) {
+        readTagsFile();
+        return sTagNames.get(tag);
+    }
+
+    /**
+     * Get the event type tag code associated with an event name.
+     * @param name of event to look up
+     * @return the tag code, or -1 if no tag has that name
+     */
+    public static int getTagCode(String name) {
+        readTagsFile();
+        Integer code = sTagCodes.get(name);
+        return code != null ? code : -1;
+    }
+
+    /**
+     * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
+     */
+    private static synchronized void readTagsFile() {
+        if (sTagCodes != null && sTagNames != null) return;
+
+        sTagCodes = new HashMap<String, Integer>();
+        sTagNames = new HashMap<Integer, String>();
+
+        Pattern comment = Pattern.compile(COMMENT_PATTERN);
+        Pattern tag = Pattern.compile(TAG_PATTERN);
+        BufferedReader reader = null;
+        String line;
+
+        try {
+            reader = new BufferedReader(new FileReader(TAGS_FILE), 256);
+            while ((line = reader.readLine()) != null) {
+                if (comment.matcher(line).matches()) continue;
+
+                Matcher m = tag.matcher(line);
+                if (!m.matches()) {
+                    Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line);
+                    continue;
+                }
+
+                try {
+                    int num = Integer.parseInt(m.group(1));
+                    String name = m.group(2);
+                    sTagCodes.put(name, num);
+                    sTagNames.put(num, name);
+                } catch (NumberFormatException e) {
+                    Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
+                }
+            }
+        } catch (IOException e) {
+            Log.wtf(TAG, "Error reading " + TAGS_FILE, e);
+            // Leave the maps existing but unpopulated
+        } finally {
+            try { if (reader != null) reader.close(); } catch (IOException e) {}
+        }
+    }
 }
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index be905e3..98868f7 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -25,16 +25,14 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-/** Parsed representation of /etc/event-log-tags. */
+/**
+ * to-bo-deprecated: This class is no longer functional.
+ * Use {@link android.util.EventLog} instead.
+ */
 public class EventLogTags {
-    private final static String TAG = "EventLogTags";
-
-    private final static String TAGS_FILE = "/etc/event-log-tags";
-
     public static class Description {
         public final int mTag;
         public final String mName;
-        // TODO: Parse parameter descriptions when anyone has a use for them.
 
         Description(int tag, String name) {
             mTag = tag;
@@ -42,49 +40,11 @@
         }
     }
 
-    private final static Pattern COMMENT_PATTERN = Pattern.compile(
-            "^\\s*(#.*)?$");
+    public EventLogTags() throws IOException {}
 
-    private final static Pattern TAG_PATTERN = Pattern.compile(
-            "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$");
+    public EventLogTags(BufferedReader input) throws IOException {}
 
-    private final HashMap<String, Description> mNameMap =
-            new HashMap<String, Description>();
+    public Description get(String name) { return null; }
 
-    private final HashMap<Integer, Description> mTagMap =
-            new HashMap<Integer, Description>();
-
-    public EventLogTags() throws IOException {
-        this(new BufferedReader(new FileReader(TAGS_FILE), 256));
-    }
-
-    public EventLogTags(BufferedReader input) throws IOException {
-        String line;
-        while ((line = input.readLine()) != null) {
-            Matcher m = COMMENT_PATTERN.matcher(line);
-            if (m.matches()) continue;
-
-            m = TAG_PATTERN.matcher(line);
-            if (m.matches()) {
-                try {
-                    int tag = Integer.parseInt(m.group(1));
-                    Description d = new Description(tag, m.group(2));
-                    mNameMap.put(d.mName, d);
-                    mTagMap.put(d.mTag, d);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "Error in event log tags entry: " + line, e);
-                }
-            } else {
-                Log.e(TAG, "Can't parse event log tags entry: " + line);
-            }
-        }
-    }
-
-    public Description get(String name) {
-        return mNameMap.get(name);
-    }
-
-    public Description get(int tag) {
-        return mTagMap.get(tag);
-    }
+    public Description get(int tag) { return null; }
 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 248ed03..60d8e72 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1636,6 +1636,7 @@
             if (mDataChanged) return;
 
             if (mAdapter != null && mItemCount > 0 &&
+                    mClickMotionPosition != INVALID_POSITION &&
                     mClickMotionPosition < mAdapter.getCount() && sameWindow()) {
                 performItemClick(mChild, mClickMotionPosition, getAdapter().getItemId(
                         mClickMotionPosition));
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c115073..3003580 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -26,6 +26,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -37,7 +38,6 @@
 import android.view.LayoutInflater.Filter;
 import android.view.View.OnClickListener;
 
-import java.lang.Class;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -283,6 +283,7 @@
         static final int CHAR_SEQUENCE = 10;
         static final int URI = 11;
         static final int BITMAP = 12;
+        static final int BUNDLE = 13;
 
         int viewId;
         String methodName;
@@ -342,6 +343,9 @@
                 case BITMAP:
                     this.value = Bitmap.CREATOR.createFromParcel(in);
                     break;
+                case BUNDLE:
+                    this.value = in.readBundle();
+                    break;
                 default:
                     break;
             }
@@ -394,6 +398,9 @@
                 case BITMAP:
                     ((Bitmap)this.value).writeToParcel(out, flags);
                     break;
+                case BUNDLE:
+                    out.writeBundle((Bundle) this.value);
+                    break;
                 default:
                     break;
             }
@@ -425,6 +432,8 @@
                     return Uri.class;
                 case BITMAP:
                     return Bitmap.class;
+                case BUNDLE:
+                    return Bundle.class;
                 default:
                     return null;
             }
@@ -886,6 +895,17 @@
     }
 
     /**
+     * Call a method taking one Bundle on a view in the layout for this RemoteViews.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param methodName The name of the method to call.
+     * @param value The value to pass to the method.
+     */
+    public void setBundle(int viewId, String methodName, Bundle value) {
+        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BUNDLE, value));
+    }
+
+    /**
      * Inflates the view hierarchy represented by this object and applies
      * all of the actions.
      * 
diff --git a/core/java/com/android/internal/os/RecoverySystem.java b/core/java/com/android/internal/os/RecoverySystem.java
deleted file mode 100644
index 3aca683..0000000
--- a/core/java/com/android/internal/os/RecoverySystem.java
+++ /dev/null
@@ -1,143 +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.internal.os;
-
-import android.os.FileUtils;
-import android.os.Power;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Utility class for interacting with the Android recovery partition.
- * The recovery partition is a small standalone system which can perform
- * operations that are difficult while the main system is running, like
- * upgrading system software or reformatting the data partition.
- * Note that most of these operations must be run as root.
- *
- * @hide
- */
-public class RecoverySystem {
-    private static final String TAG = "RecoverySystem";  // for logging
-
-    // Used to communicate with recovery.  See commands/recovery/recovery.c.
-    private static File RECOVERY_DIR = new File("/cache/recovery");
-    private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
-    private static File LOG_FILE = new File(RECOVERY_DIR, "log");
-
-    // Length limits for reading files.
-    private static int LOG_FILE_MAX_LENGTH = 8 * 1024;
-
-    /**
-     * Reboot into the recovery system to install a system update.
-     * @param update package to install (must be in /cache or /data).
-     * @throws IOException if something goes wrong.
-     */
-    public static void rebootAndUpdate(File update) throws IOException {
-        String path = update.getCanonicalPath();
-        if (path.startsWith("/cache/")) {
-            path = "CACHE:" + path.substring(7);
-        } else if (path.startsWith("/data/")) {
-            path = "DATA:" + path.substring(6);
-        } else {
-            throw new IllegalArgumentException(
-                    "Must start with /cache or /data: " + path);
-        }
-        bootCommand("--update_package=" + path);
-    }
-
-    /**
-     * Reboot into the recovery system to wipe the /data partition.
-     * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
-     * @throws IOException if something goes wrong.
-     */
-    public static void rebootAndWipe() throws IOException {
-        bootCommand("--wipe_data");
-    }
-
-    /**
-     * Reboot into the recovery system to wipe the /data partition and toggle
-     * Encrypted File Systems on/off.
-     * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
-     * @throws IOException if something goes wrong.
-     * @hide
-     */
-    public static void rebootAndToggleEFS(boolean efsEnabled) throws IOException {
-        if (efsEnabled) {
-            bootCommand("--set_encrypted_filesystem=on");
-        } else {
-            bootCommand("--set_encrypted_filesystem=off");
-        }
-    }
-
-    /**
-     * Reboot into the recovery system with the supplied argument.
-     * @param arg to pass to the recovery utility.
-     * @throws IOException if something goes wrong.
-     */
-    private static void bootCommand(String arg) throws IOException {
-        RECOVERY_DIR.mkdirs();  // In case we need it
-        COMMAND_FILE.delete();  // In case it's not writable
-        LOG_FILE.delete();
-
-        FileWriter command = new FileWriter(COMMAND_FILE);
-        try {
-            command.write(arg);
-            command.write("\n");
-        } finally {
-            command.close();
-        }
-
-        // Having written the command file, go ahead and reboot
-        Power.reboot("recovery");
-        throw new IOException("Reboot failed (no permissions?)");
-    }
-
-    /**
-     * Called after booting to process and remove recovery-related files.
-     * @return the log file from recovery, or null if none was found.
-     */
-    public static String handleAftermath() {
-        // Record the tail of the LOG_FILE
-        String log = null;
-        try {
-            log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
-        } catch (FileNotFoundException e) {
-            Log.i(TAG, "No recovery log file");
-        } catch (IOException e) {
-            Log.e(TAG, "Error reading recovery log", e);
-        }
-
-        // Delete everything in RECOVERY_DIR
-        String[] names = RECOVERY_DIR.list();
-        for (int i = 0; names != null && i < names.length; i++) {
-            File f = new File(RECOVERY_DIR, names[i]);
-            if (!f.delete()) {
-                Log.e(TAG, "Can't delete: " + f);
-            } else {
-                Log.i(TAG, "Deleted: " + f);
-            }
-        }
-
-        return log;
-    }
-}
diff --git a/core/java/com/android/internal/widget/VerticalTextSpinner.java b/core/java/com/android/internal/widget/VerticalTextSpinner.java
deleted file mode 100644
index 50c528c..0000000
--- a/core/java/com/android/internal/widget/VerticalTextSpinner.java
+++ /dev/null
@@ -1,467 +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.internal.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-public class VerticalTextSpinner extends View {
-
-    private static final int SELECTOR_ARROW_HEIGHT = 15;
-    
-    private static final int TEXT_SPACING = 18;
-    private static final int TEXT_MARGIN_RIGHT = 25;
-    private static final int TEXT_SIZE = 22;
-    
-    /* Keep the calculations as this is really a for loop from
-     * -2 to 2 but precalculated so we don't have to do in the onDraw.
-     */
-    private static final int TEXT1_Y = (TEXT_SIZE * (-2 + 2)) + (TEXT_SPACING * (-2 + 1));
-    private static final int TEXT2_Y = (TEXT_SIZE * (-1 + 2)) + (TEXT_SPACING * (-1 + 1));
-    private static final int TEXT3_Y = (TEXT_SIZE * (0 + 2)) + (TEXT_SPACING * (0 + 1));
-    private static final int TEXT4_Y = (TEXT_SIZE * (1 + 2)) + (TEXT_SPACING * (1 + 1));
-    private static final int TEXT5_Y = (TEXT_SIZE * (2 + 2)) + (TEXT_SPACING * (2 + 1));
-    
-    private static final int SCROLL_MODE_NONE = 0;
-    private static final int SCROLL_MODE_UP = 1;
-    private static final int SCROLL_MODE_DOWN = 2;
-    
-    private static final long DEFAULT_SCROLL_INTERVAL_MS = 400;
-    private static final int SCROLL_DISTANCE = TEXT_SIZE + TEXT_SPACING;
-    private static final int MIN_ANIMATIONS = 4;
-    
-    private final Drawable mBackgroundFocused;
-    private final Drawable mSelectorFocused;
-    private final Drawable mSelectorNormal;
-    private final int mSelectorDefaultY;
-    private final int mSelectorMinY;
-    private final int mSelectorMaxY;
-    private final int mSelectorHeight;
-    private final TextPaint mTextPaintDark;
-    private final TextPaint mTextPaintLight;
-    
-    private int mSelectorY;
-    private Drawable mSelector;
-    private int mDownY;
-    private boolean isDraggingSelector;
-    private int mScrollMode;
-    private long mScrollInterval;
-    private boolean mIsAnimationRunning;
-    private boolean mStopAnimation;
-    private boolean mWrapAround = true;
-    
-    private int mTotalAnimatedDistance;
-    private int mNumberOfAnimations;
-    private long mDelayBetweenAnimations;
-    private int mDistanceOfEachAnimation;
-    
-    private String[] mTextList;
-    private int mCurrentSelectedPos;
-    private OnChangedListener mListener;
-    
-    private String mText1;
-    private String mText2;
-    private String mText3;
-    private String mText4;
-    private String mText5;
-    
-    public interface OnChangedListener {
-        void onChanged(
-                VerticalTextSpinner spinner, int oldPos, int newPos, String[] items);
-    }
-    
-    public VerticalTextSpinner(Context context) {
-        this(context, null);
-    }
-    
-    public VerticalTextSpinner(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public VerticalTextSpinner(Context context, AttributeSet attrs,
-            int defStyle) {
-        super(context, attrs, defStyle);
-        
-        mBackgroundFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_background);
-        mSelectorFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_selected);
-        mSelectorNormal = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_unselected);
-        
-        mSelectorHeight = mSelectorFocused.getIntrinsicHeight();
-        mSelectorDefaultY = (mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight) / 2;
-        mSelectorMinY = 0;
-        mSelectorMaxY = mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight;
-        
-        mSelector = mSelectorNormal;
-        mSelectorY = mSelectorDefaultY;
-        
-        mTextPaintDark = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-        mTextPaintDark.setTextSize(TEXT_SIZE);
-        mTextPaintDark.setColor(context.getResources().getColor(com.android.internal.R.color.primary_text_light));
-        
-        mTextPaintLight = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-        mTextPaintLight.setTextSize(TEXT_SIZE);
-        mTextPaintLight.setColor(context.getResources().getColor(com.android.internal.R.color.secondary_text_dark));
-        
-        mScrollMode = SCROLL_MODE_NONE;
-        mScrollInterval = DEFAULT_SCROLL_INTERVAL_MS;
-        calculateAnimationValues();
-    }
-    
-    public void setOnChangeListener(OnChangedListener listener) {
-        mListener = listener;
-    }
-    
-    public void setItems(String[] textList) {
-        mTextList = textList;
-        calculateTextPositions();
-    }
-    
-    public void setSelectedPos(int selectedPos) {
-        mCurrentSelectedPos = selectedPos;
-        calculateTextPositions();
-        postInvalidate();
-    }
-    
-    public void setScrollInterval(long interval) {
-        mScrollInterval = interval;
-        calculateAnimationValues();
-    }
-    
-    public void setWrapAround(boolean wrap) {
-        mWrapAround = wrap;
-    }
-    
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        
-        /* This is a bit confusing, when we get the key event
-         * DPAD_DOWN we actually roll the spinner up. When the
-         * key event is DPAD_UP we roll the spinner down.
-         */
-        if ((keyCode == KeyEvent.KEYCODE_DPAD_UP) && canScrollDown()) {
-            mScrollMode = SCROLL_MODE_DOWN;
-            scroll();
-            mStopAnimation = true;
-            return true;
-        } else if ((keyCode == KeyEvent.KEYCODE_DPAD_DOWN) && canScrollUp()) {
-            mScrollMode = SCROLL_MODE_UP;
-            scroll();
-            mStopAnimation = true;
-            return true;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-
-    private boolean canScrollDown() {
-        return (mCurrentSelectedPos > 0) || mWrapAround;
-    }
-
-    private boolean canScrollUp() {
-        return ((mCurrentSelectedPos < (mTextList.length - 1)) || mWrapAround);
-    }
-    
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction,
-            Rect previouslyFocusedRect) {
-        if (gainFocus) {
-            setBackgroundDrawable(mBackgroundFocused);
-            mSelector = mSelectorFocused;
-        } else {
-            setBackgroundDrawable(null);
-            mSelector = mSelectorNormal;
-            mSelectorY = mSelectorDefaultY;
-        }
-    }
-    
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {        
-        final int action = event.getAction();
-        final int y = (int) event.getY();
-
-        switch (action) {
-        case MotionEvent.ACTION_DOWN:
-            requestFocus();
-            mDownY = y;
-            isDraggingSelector = (y >= mSelectorY) && (y <= (mSelectorY + mSelector.getIntrinsicHeight()));
-            break;
-
-        case MotionEvent.ACTION_MOVE:
-            if (isDraggingSelector) {
-                int top = mSelectorDefaultY + (y - mDownY);
-                if (top <= mSelectorMinY && canScrollDown()) {
-                    mSelectorY = mSelectorMinY;
-                    mStopAnimation = false;
-                    if (mScrollMode != SCROLL_MODE_DOWN) {
-                        mScrollMode = SCROLL_MODE_DOWN;
-                        scroll();
-                    }
-                } else if (top >= mSelectorMaxY && canScrollUp()) {
-                    mSelectorY = mSelectorMaxY;
-                    mStopAnimation = false;
-                    if (mScrollMode != SCROLL_MODE_UP) {
-                        mScrollMode = SCROLL_MODE_UP;
-                        scroll();
-                    }
-                } else {
-                    mSelectorY = top;
-                    mStopAnimation = true;
-                }
-            }
-            break;
-            
-        case MotionEvent.ACTION_UP:
-        case MotionEvent.ACTION_CANCEL:
-        default:
-            mSelectorY = mSelectorDefaultY;
-            mStopAnimation = true;
-            invalidate();
-            break;
-        }
-        return true;
-    }
-    
-    @Override
-    protected void onDraw(Canvas canvas) {
-        
-        /* The bounds of the selector */
-        final int selectorLeft = 0;
-        final int selectorTop = mSelectorY;
-        final int selectorRight = mMeasuredWidth;
-        final int selectorBottom = mSelectorY + mSelectorHeight;
-        
-        /* Draw the selector */
-        mSelector.setBounds(selectorLeft, selectorTop, selectorRight, selectorBottom);
-        mSelector.draw(canvas);
-        
-        if (mTextList == null) {
-            
-            /* We're not setup with values so don't draw anything else */
-            return;
-        }
-        
-        final TextPaint textPaintDark = mTextPaintDark;
-        if (hasFocus()) {
-            
-            /* The bounds of the top area where the text should be light */
-            final int topLeft = 0;
-            final int topTop = 0;
-            final int topRight = selectorRight;
-            final int topBottom = selectorTop + SELECTOR_ARROW_HEIGHT;
-
-            /* Assign a bunch of local finals for performance */
-            final String text1 = mText1;
-            final String text2 = mText2;
-            final String text3 = mText3;
-            final String text4 = mText4;
-            final String text5 = mText5;
-            final TextPaint textPaintLight = mTextPaintLight;
-            
-            /*
-             * Draw the 1st, 2nd and 3rd item in light only, clip it so it only
-             * draws in the area above the selector
-             */
-            canvas.save();
-            canvas.clipRect(topLeft, topTop, topRight, topBottom);
-            drawText(canvas, text1, TEXT1_Y
-                    + mTotalAnimatedDistance, textPaintLight);
-            drawText(canvas, text2, TEXT2_Y
-                    + mTotalAnimatedDistance, textPaintLight);
-            drawText(canvas, text3,
-                    TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
-            canvas.restore();
-
-            /*
-             * Draw the 2nd, 3rd and 4th clipped to the selector bounds in dark
-             * paint
-             */
-            canvas.save();
-            canvas.clipRect(selectorLeft, selectorTop + SELECTOR_ARROW_HEIGHT,
-                    selectorRight, selectorBottom - SELECTOR_ARROW_HEIGHT);
-            drawText(canvas, text2, TEXT2_Y
-                    + mTotalAnimatedDistance, textPaintDark);
-            drawText(canvas, text3,
-                    TEXT3_Y + mTotalAnimatedDistance, textPaintDark);
-            drawText(canvas, text4,
-                    TEXT4_Y + mTotalAnimatedDistance, textPaintDark);
-            canvas.restore();
-
-            /* The bounds of the bottom area where the text should be light */
-            final int bottomLeft = 0;
-            final int bottomTop = selectorBottom - SELECTOR_ARROW_HEIGHT;
-            final int bottomRight = selectorRight;
-            final int bottomBottom = mMeasuredHeight;
-
-            /*
-             * Draw the 3rd, 4th and 5th in white text, clip it so it only draws
-             * in the area below the selector.
-             */
-            canvas.save();
-            canvas.clipRect(bottomLeft, bottomTop, bottomRight, bottomBottom);
-            drawText(canvas, text3,
-                    TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
-            drawText(canvas, text4,
-                    TEXT4_Y + mTotalAnimatedDistance, textPaintLight);
-            drawText(canvas, text5,
-                    TEXT5_Y + mTotalAnimatedDistance, textPaintLight);
-            canvas.restore();
-            
-        } else {
-            drawText(canvas, mText3, TEXT3_Y, textPaintDark);
-        }
-        if (mIsAnimationRunning) {
-            if ((Math.abs(mTotalAnimatedDistance) + mDistanceOfEachAnimation) > SCROLL_DISTANCE) {
-                mTotalAnimatedDistance = 0;
-                if (mScrollMode == SCROLL_MODE_UP) {
-                    int oldPos = mCurrentSelectedPos;
-                    int newPos = getNewIndex(1);
-                    if (newPos >= 0) {
-                        mCurrentSelectedPos = newPos;
-                        if (mListener != null) {
-                            mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
-                        }
-                    }
-                    if (newPos < 0 || ((newPos >= mTextList.length - 1) && !mWrapAround)) {
-                        mStopAnimation = true;
-                    }
-                    calculateTextPositions();
-                } else if (mScrollMode == SCROLL_MODE_DOWN) {
-                    int oldPos = mCurrentSelectedPos;
-                    int newPos = getNewIndex(-1);
-                    if (newPos >= 0) {
-                        mCurrentSelectedPos = newPos;
-                        if (mListener != null) {
-                            mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
-                        }
-                    }
-                    if (newPos < 0 || (newPos == 0 && !mWrapAround)) {
-                        mStopAnimation = true;
-                    }
-                    calculateTextPositions();
-                }
-                if (mStopAnimation) {
-                    final int previousScrollMode = mScrollMode;
-                    
-                    /* No longer scrolling, we wait till the current animation
-                     * completes then we stop.
-                     */
-                    mIsAnimationRunning = false;
-                    mStopAnimation = false;
-                    mScrollMode = SCROLL_MODE_NONE;
-                    
-                    /* If the current selected item is an empty string
-                     * scroll past it.
-                     */
-                    if ("".equals(mTextList[mCurrentSelectedPos])) {
-                       mScrollMode = previousScrollMode;
-                       scroll();
-                       mStopAnimation = true;
-                    }
-                }
-            } else {
-                if (mScrollMode == SCROLL_MODE_UP) {
-                    mTotalAnimatedDistance -= mDistanceOfEachAnimation;
-                } else if (mScrollMode == SCROLL_MODE_DOWN) {
-                    mTotalAnimatedDistance += mDistanceOfEachAnimation;
-                }
-            }
-            if (mDelayBetweenAnimations > 0) {
-                postInvalidateDelayed(mDelayBetweenAnimations);
-            } else {
-                invalidate();
-            }
-        }
-    }
-
-    /**
-     * Called every time the text items or current position
-     * changes. We calculate store we don't have to calculate
-     * onDraw.
-     */
-    private void calculateTextPositions() {
-        mText1 = getTextToDraw(-2);
-        mText2 = getTextToDraw(-1);
-        mText3 = getTextToDraw(0);
-        mText4 = getTextToDraw(1);
-        mText5 = getTextToDraw(2);
-    }
-    
-    private String getTextToDraw(int offset) {
-        int index = getNewIndex(offset);
-        if (index < 0) {
-            return "";
-        }
-        return mTextList[index];
-    }
-
-    private int getNewIndex(int offset) {
-        int index = mCurrentSelectedPos + offset;
-        if (index < 0) {
-            if (mWrapAround) {
-                index += mTextList.length;
-            } else {
-                return -1;
-            }
-        } else if (index >= mTextList.length) {
-            if (mWrapAround) {
-                index -= mTextList.length;
-            } else {
-                return -1;
-            }
-        }
-        return index;
-    }
-    
-    private void scroll() {
-        if (mIsAnimationRunning) {
-            return;
-        }
-        mTotalAnimatedDistance = 0;
-        mIsAnimationRunning = true;
-        invalidate();
-    }
-
-    private void calculateAnimationValues() {
-        mNumberOfAnimations = (int) mScrollInterval / SCROLL_DISTANCE;
-        if (mNumberOfAnimations < MIN_ANIMATIONS) {
-            mNumberOfAnimations = MIN_ANIMATIONS;
-            mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
-            mDelayBetweenAnimations = 0;
-        } else {
-            mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
-            mDelayBetweenAnimations = mScrollInterval / mNumberOfAnimations;
-        }
-    }
-    
-    private void drawText(Canvas canvas, String text, int y, TextPaint paint) {
-        int width = (int) paint.measureText(text);
-        int x = getMeasuredWidth() - width - TEXT_MARGIN_RIGHT;
-        canvas.drawText(text, x, y, paint);
-    }
-    
-    public int getCurrentSelectedPos() {
-        return mCurrentSelectedPos;
-    }
-}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 34b7c89..78356cf 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -21,13 +21,6 @@
 #include "jni.h"
 #include "cutils/logger.h"
 
-#define END_DELIMITER '\n'
-#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
-#define LONG_BUFFER_SIZE (sizeof(jbyte)+sizeof(jlong)+sizeof(END_DELIMITER))
-#define INITAL_BUFFER_CAPACITY 256
-
-#define MAX(a,b) ((a>b)?a:b)
-
 namespace android {
 
 static jclass gCollectionClass;
@@ -47,107 +40,6 @@
 
 static jclass gStringClass;
 
-struct ByteBuf {
-    size_t len;
-    size_t capacity;
-    uint8_t* buf;
-
-    ByteBuf(size_t initSize) {
-        buf = (uint8_t*)malloc(initSize);
-        len = 0;
-        capacity = initSize;
-    }
-
-    ~ByteBuf() {
-        free(buf);
-    }
-
-    bool ensureExtraCapacity(size_t extra) {
-        size_t spaceNeeded = len + extra;
-        if (spaceNeeded > capacity) {
-            size_t newCapacity = MAX(spaceNeeded, 2 * capacity);
-            void* newBuf = realloc(buf, newCapacity);
-            if (newBuf == NULL) {
-                return false;
-            }
-            capacity = newCapacity;
-            buf = (uint8_t*)newBuf;
-            return true;
-        } else {
-            return true;
-        }
-    }
-
-    void putIntEvent(jint value) {
-        bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
-        buf[len++] = EVENT_TYPE_INT;
-        memcpy(buf+len, &value, sizeof(jint));
-        len += sizeof(jint);
-    }
-
-    void putByte(uint8_t value) {
-        bool succeeded = ensureExtraCapacity(sizeof(uint8_t));
-        buf[len++] = value;
-    }
-
-    void putLongEvent(jlong value) {
-        bool succeeded = ensureExtraCapacity(LONG_BUFFER_SIZE);
-        buf[len++] = EVENT_TYPE_LONG;
-        memcpy(buf+len, &value, sizeof(jlong));
-        len += sizeof(jlong);
-    }
-
-
-    void putStringEvent(JNIEnv* env, jstring value) {
-        const char* strValue = env->GetStringUTFChars(value, NULL);
-        uint32_t strLen = strlen(strValue); //env->GetStringUTFLength(value);
-        bool succeeded = ensureExtraCapacity(1 + sizeof(uint32_t) + strLen);
-        buf[len++] = EVENT_TYPE_STRING;
-        memcpy(buf+len, &strLen, sizeof(uint32_t));
-        len += sizeof(uint32_t);
-        memcpy(buf+len, strValue, strLen);
-        env->ReleaseStringUTFChars(value, strValue);
-        len += strLen;
-    }
-
-    void putList(JNIEnv* env, jobject list) {
-        jobjectArray items = (jobjectArray) env->GetObjectField(list, gListItemsID);
-        if (items == NULL) {
-            jniThrowException(env, "java/lang/NullPointerException", NULL);
-            return;
-        }
-
-        jsize numItems = env->GetArrayLength(items);
-        putByte(EVENT_TYPE_LIST);
-        putByte(numItems);
-        // We'd like to call GetPrimitveArrayCritical() but that might
-        // not be safe since we're going to be doing some I/O
-        for (int i = 0; i < numItems; i++) {
-            jobject item = env->GetObjectArrayElement(items, i);
-            if (env->IsInstanceOf(item, gIntegerClass)) {
-                jint intVal = env->GetIntField(item, gIntegerValueID);
-                putIntEvent(intVal);
-            } else if (env->IsInstanceOf(item, gLongClass)) {
-                jlong longVal = env->GetLongField(item, gLongValueID);
-                putLongEvent(longVal);
-            } else if (env->IsInstanceOf(item, gStringClass)) {
-                putStringEvent(env, (jstring)item);
-            } else if (env->IsInstanceOf(item, gListClass)) {
-                putList(env, item);
-            } else {
-                jniThrowException(
-                        env,
-                        "java/lang/IllegalArgumentException",
-                        "Attempt to log an illegal item type.");
-                return;
-            }
-            env->DeleteLocalRef(item);
-        }
-
-        env->DeleteLocalRef(items);
-    }
-};
-
 /*
  * In class android.util.EventLog:
  *  static native int writeEvent(int tag, int value)
@@ -170,41 +62,80 @@
 
 /*
  * In class android.util.EventLog:
- *  static native int writeEvent(long tag, List value)
- */
-static jint android_util_EventLog_writeEvent_List(JNIEnv* env, jobject clazz,
-                                                  jint tag, jobject value) {
-    if (value == NULL) {
-        jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
-        env->ThrowNew(clazz, "writeEvent needs a value.");
-        return -1;
-    }
-    ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
-    byteBuf.putList(env, value);
-    byteBuf.putByte((uint8_t)END_DELIMITER);
-    int numBytesPut = byteBuf.len;
-    int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
-    return bytesWritten;
-}
-
-/*
- * In class android.util.EventLog:
  *  static native int writeEvent(int tag, String value)
  */
 static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
                                                     jint tag, jstring value) {
+    uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+
+    // Don't throw NPE -- I feel like it's sort of mean for a logging function
+    // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+    const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
+    jint len = strlen(str);
+    const int max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
+    if (len > max) len = max;
+
+    buf[0] = EVENT_TYPE_STRING;
+    memcpy(&buf[1], &len, sizeof(len));
+    memcpy(&buf[1 + sizeof(len)], str, len);
+    buf[1 + sizeof(len) + len] = '\n';
+
+    if (value != NULL) env->ReleaseStringUTFChars(value, str);
+    return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
+}
+
+/*
+ * In class android.util.EventLog:
+ *  static native int writeEvent(long tag, Object... value)
+ */
+static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+                                                   jint tag, jobjectArray value) {
     if (value == NULL) {
-        jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
-        env->ThrowNew(clazz, "logEvent needs a value.");
-        return -1;
+        return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
     }
 
-    ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
-    byteBuf.putStringEvent(env, value);
-    byteBuf.putByte((uint8_t)END_DELIMITER);
-    int numBytesPut = byteBuf.len;
-    int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
-    return bytesWritten;
+    uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD];
+    const size_t max = sizeof(buf) - 1;  // leave room for final newline
+    size_t pos = 2;  // Save room for type tag & array count
+
+    jsize copied = 0, num = env->GetArrayLength(value);
+    for (; copied < num && copied < 256; ++copied) {
+        jobject item = env->GetObjectArrayElement(value, copied);
+        if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
+            if (pos + 1 + sizeof(jint) > max) break;
+            const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
+            jint len = strlen(str);
+            if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
+            buf[pos++] = EVENT_TYPE_STRING;
+            memcpy(&buf[pos], &len, sizeof(len));
+            memcpy(&buf[pos + sizeof(len)], str, len);
+            pos += sizeof(len) + len;
+            if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+        } else if (env->IsInstanceOf(item, gIntegerClass)) {
+            jint intVal = env->GetIntField(item, gIntegerValueID);
+            if (pos + 1 + sizeof(intVal) > max) break;
+            buf[pos++] = EVENT_TYPE_INT;
+            memcpy(&buf[pos], &intVal, sizeof(intVal));
+            pos += sizeof(intVal);
+        } else if (env->IsInstanceOf(item, gLongClass)) {
+            jlong longVal = env->GetLongField(item, gLongValueID);
+            if (pos + 1 + sizeof(longVal) > max) break;
+            buf[pos++] = EVENT_TYPE_LONG;
+            memcpy(&buf[pos], &longVal, sizeof(longVal));
+            pos += sizeof(longVal);
+        } else {
+            jniThrowException(env,
+                    "java/lang/IllegalArgumentException",
+                    "Invalid payload item type");
+            return -1;
+        }
+        env->DeleteLocalRef(item);
+    }
+
+    buf[0] = EVENT_TYPE_LIST;
+    buf[1] = copied;
+    buf[pos++] = '\n';
+    return android_bWriteLog(tag, buf, pos);
 }
 
 /*
@@ -276,81 +207,6 @@
 }
 
 /*
- * In class android.util.EventLog:
- *  static native void readEvents(String path, Collection<Event> output)
- *
- *  Reads events from a file (See Checkin.Aggregation). Events are stored in
- *  native raw format (logger_entry + payload).
- */
-static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
-            jobject out) {
-    if (path == NULL || out == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", NULL);
-        return;
-    }
-
-    const char *pathString = env->GetStringUTFChars(path, 0);
-    int fd = open(pathString, O_RDONLY | O_NONBLOCK);
-    env->ReleaseStringUTFChars(path, pathString);
-
-    if (fd < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-
-    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
-    for (;;) {
-        // read log entry structure from file
-        int len = read(fd, buf, sizeof(logger_entry));
-        if (len == 0) {
-            break; // end of file
-        } else if (len < 0) {
-            jniThrowIOException(env, errno);
-        } else if ((size_t) len < sizeof(logger_entry)) {
-            jniThrowException(env, "java/io/IOException", "Event header too short");
-            break;
-        }
-
-        // read event payload
-        logger_entry* entry = (logger_entry*) buf;
-        if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
-            jniThrowException(env,
-                    "java/lang/IllegalArgumentException",
-                    "Too much data for event payload. Corrupt file?");
-            break;
-        }
-
-        len = read(fd, buf + sizeof(logger_entry), entry->len);
-        if (len == 0) {
-            break; // end of file
-        } else if (len < 0) {
-            jniThrowIOException(env, errno);
-        } else if ((size_t) len < entry->len) {
-            jniThrowException(env, "java/io/IOException", "Event payload too short");
-            break;
-        }
-
-        // create EventLog$Event and add it to the collection
-        int buffer_size = sizeof(logger_entry) + entry->len;
-        jbyteArray array = env->NewByteArray(buffer_size);
-        if (array == NULL) break;
-
-        jbyte *bytes = env->GetByteArrayElements(array, NULL);
-        memcpy(bytes, buf, buffer_size);
-        env->ReleaseByteArrayElements(array, bytes, 0);
-
-        jobject event = env->NewObject(gEventClass, gEventInitID, array);
-        if (event == NULL) break;
-
-        env->CallBooleanMethod(out, gCollectionAddID, event);
-        env->DeleteLocalRef(event);
-        env->DeleteLocalRef(array);
-    }
-
-    close(fd);
-}
-
-/*
  * JNI registration.
  */
 static JNINativeMethod gRegisterMethods[] = {
@@ -362,22 +218,17 @@
       (void*) android_util_EventLog_writeEvent_String
     },
     { "writeEvent",
-      "(ILandroid/util/EventLog$List;)I",
-      (void*) android_util_EventLog_writeEvent_List
+      "(I[Ljava/lang/Object;)I",
+      (void*) android_util_EventLog_writeEvent_Array
     },
     { "readEvents",
       "([ILjava/util/Collection;)V",
       (void*) android_util_EventLog_readEvents
     },
-    { "readEvents",
-      "(Ljava/lang/String;Ljava/util/Collection;)V",
-      (void*) android_util_EventLog_readEventsFile
-    }
 };
 
 static struct { const char *name; jclass *clazz; } gClasses[] = {
     { "android/util/EventLog$Event", &gEventClass },
-    { "android/util/EventLog$List", &gListClass },
     { "java/lang/Integer", &gIntegerClass },
     { "java/lang/Long", &gLongClass },
     { "java/lang/String", &gStringClass },
@@ -386,7 +237,6 @@
 
 static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
     { &gIntegerClass, "value", "I", &gIntegerValueID },
-    { &gListClass, "mItems", "[Ljava/lang/Object;", &gListItemsID },
     { &gLongClass, "value", "J", &gLongValueID },
 };
 
@@ -430,4 +280,3 @@
 }
 
 }; // namespace android
-
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 78cb86d..7d11148 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -24,7 +24,7 @@
 # since these resources will be used by many apps.
 LOCAL_AAPT_FLAGS := -x
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 # Install this alongside the libraries.
 LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72ad324..d202372 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -556,12 +556,30 @@
         android:label="@string/permlab_changeConfiguration"
         android:description="@string/permdesc_changeConfiguration" />
 
-    <!-- Allows an application to restart other applications. -->
+    <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
+        API is no longer supported. -->
     <permission android:name="android.permission.RESTART_PACKAGES"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_restartPackages"
-        android:description="@string/permdesc_restartPackages" />
+        android:protectionLevel="normal"
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses" />
+
+    <!-- Allows an application to call
+        {@link android.app.ActivityManager#killBackgroundProcesses}. -->
+    <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="normal"
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses" />
+
+    <!-- Allows an application to call
+        {@link android.app.ActivityManager#forceStopPackage}.
+        @hide -->
+    <permission android:name="android.permission.FORCE_STOP_PACKAGES"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_forceStopPackages"
+        android:description="@string/permdesc_forceStopPackages" />
 
     <!-- Allows an application to retrieve state dump information from system
          services. -->
diff --git a/core/res/res/drawable-hdpi/pickerbox_background.png b/core/res/res/drawable-hdpi/pickerbox_background.png
deleted file mode 100644
index 9315a31..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_selected.9.png b/core/res/res/drawable-hdpi/pickerbox_selected.9.png
deleted file mode 100644
index a88ec63..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_unselected.9.png b/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
deleted file mode 100644
index 9f6b7cb..0000000
--- a/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_background.png b/core/res/res/drawable-mdpi/pickerbox_background.png
deleted file mode 100644
index 6494cd8..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_background.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_selected.9.png b/core/res/res/drawable-mdpi/pickerbox_selected.9.png
deleted file mode 100644
index d986a31..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pickerbox_unselected.9.png b/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
deleted file mode 100644
index 27ec6b9..0000000
--- a/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/pickerbox.xml b/core/res/res/drawable/pickerbox.xml
deleted file mode 100644
index 9cb2436..0000000
--- a/core/res/res/drawable/pickerbox.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/pickerbox_selected" />
-    <item android:drawable="@drawable/pickerbox_unselected" />
-</selector>
-
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc354c5..4fb476b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -462,10 +462,17 @@
         size.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_restartPackages">restart other applications</string>
+    <string name="permlab_killBackgroundProcesses">kill background processes</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_restartPackages">Allows an application to
-        forcibly restart other applications.</string>
+    <string name="permdesc_killBackgroundProcesses">Allows an application to
+        kill background processes of other applications, even if memory
+        isn\'t low.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_forceStopPackages">force stop other applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_forceStopPackages">Allows an application to
+        forcibly stop other applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_forceBack">force application to close</string>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 883f64a..ec7e9da 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -45,9 +45,11 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.apis.google.com/chart?cht=p&chs=400x250&chd=t:0.3,27.7,54.2,2.9,14.8&chl=Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?cht=p&chs=400x250&chd=t:0.3,31.0,47.6,0.7,20.4&chl=Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1&chco=c4df9b,6fad0c" />
 
-<!-- f6faf2,a3c539 -->
+<!-- HISTORY
+12/14/09 http://chart.apis.google.com/chart?cht=p&chs=400x250&chd=t:0.3,27.7,54.2,2.9,14.8&chl=Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1&chco=c4df9b,6fad0c
+-->
 
 <table>
 <tr>
@@ -60,20 +62,20 @@
 </tr>
 <tr>
   <td>Android 1.5</td>
-  <td>27.7%</td>
+  <td>31.0%</td>
 </tr>
 <tr>
   <td>Android 1.6</td>
-  <td>54.2%</td></tr>
+  <td>47.6%</td></tr>
 <tr>
   <td>Android 2.0</td>
-  <td>2.9%</td>
+  <td>0.7%</td>
 </tr>
 <tr>
   <td>Android 2.0.1</td>
-  <td>14.8%</td>
+  <td>20.4%</td>
 </tr>
 </table>
 </div>
 
-<p><em>Data collected during two weeks ending on 12/14/2009</em></p>
+<p><em>Data collected during two weeks ending on 1/4/2010</em></p>
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 1324179a..10ef05a 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -298,7 +298,8 @@
               dk == DataKind.POSITION ||
               dk == DataKind.TEXTURE ||
               dk == DataKind.NORMAL ||
-              dk == DataKind.POINT_SIZE)) {
+              dk == DataKind.POINT_SIZE ||
+              dk == DataKind.USER)) {
             throw new IllegalArgumentException("Unsupported DataKind");
         }
 
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index bb2c06a..6662333 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -64,6 +64,7 @@
 void rsContextDeinitToClient(RsContext);
 
 #define RS_MAX_TEXTURE 2
+#define RS_MAX_ATTRIBS 16
 
 enum RsDataType {
     RS_TYPE_NONE,
diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Film/Android.mk
index b7f98fc..9e6ed7e 100644
--- a/libs/rs/java/Film/Android.mk
+++ b/libs/rs/java/Film/Android.mk
@@ -17,6 +17,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := optional
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk
index b6a9f10..f7e53a8 100644
--- a/libs/rs/java/Fountain/Android.mk
+++ b/libs/rs/java/Fountain/Android.mk
@@ -17,6 +17,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := optional
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
diff --git a/libs/rs/java/ImageProcessing/Android.mk b/libs/rs/java/ImageProcessing/Android.mk
index 5a844d5..833427b 100644
--- a/libs/rs/java/ImageProcessing/Android.mk
+++ b/libs/rs/java/ImageProcessing/Android.mk
@@ -17,6 +17,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := optional
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 181902b..261b827 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -274,8 +274,8 @@
 
      rsc->props.mLogTimes = getProp("debug.rs.profile");
      rsc->props.mLogScripts = getProp("debug.rs.script");
-     rsc->props.mLogObjects = getProp("debug.rs.objects");
-     rsc->props.mLogShaders = getProp("debug.rs.shaders");
+     rsc->props.mLogObjects = getProp("debug.rs.object");
+     rsc->props.mLogShaders = getProp("debug.rs.shader");
 
      ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
      if (!tlsStruct) {
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index dc3a57c..4bb7802 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -42,6 +42,8 @@
     void bindAllocation(Allocation *);
     virtual void createShader();
 
+    bool isUserProgram() const {return mUserShader.size() > 0;}
+
     void bindTexture(uint32_t slot, Allocation *);
     void bindSampler(uint32_t slot, Sampler *);
 
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index f7394a6..00f19ae 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -136,6 +136,7 @@
     }
     glActiveTexture(GL_TEXTURE0);
     mDirty = false;
+    rsc->checkError("ProgramFragment::setupGL");
 }
 
 void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, ShaderCache *sc)
@@ -170,8 +171,7 @@
 
     glActiveTexture(GL_TEXTURE0);
     mDirty = false;
-
-    //LOGE("sgl2 frag2 %x", glGetError());
+    rsc->checkError("ProgramFragment::setupGL2");
 }
 
 void ProgramFragment::loadShader(Context *rsc) {
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index b207558..2be6a7d 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -148,21 +148,21 @@
         }
         mShader.append(mUserShader);
     } else {
-        for (uint32_t ct=0; ct < mAttribCount; ct++) {
+        for (uint32_t ct=VertexArray::POSITION; ct < mAttribCount; ct++) {
             mShader.append("attribute vec4 ");
             mShader.append(mAttribNames[ct]);
             mShader.append(";\n");
         }
 
         mShader.append("void main() {\n");
-        mShader.append("  gl_Position = uni_MVP * attrib_Position;\n");
-        mShader.append("  gl_PointSize = attrib_PointSize.x;\n");
+        mShader.append("  gl_Position = uni_MVP * ATTRIB_Position;\n");
+        mShader.append("  gl_PointSize = ATTRIB_PointSize.x;\n");
 
-        mShader.append("  varColor = attrib_Color;\n");
+        mShader.append("  varColor = ATTRIB_Color;\n");
         if (mTextureMatrixEnable) {
-            mShader.append("  varTex0 = uni_TexMatrix * attrib_T0;\n");
+            mShader.append("  varTex0 = uni_TexMatrix * ATTRIB_Texture;\n");
         } else {
-            mShader.append("  varTex0 = attrib_T0;\n");
+            mShader.append("  varTex0 = ATTRIB_Texture;\n");
         }
         //mShader.append("  pos.x = pos.x / 480.0;\n");
         //mShader.append("  pos.y = pos.y / 800.0;\n");
@@ -195,7 +195,7 @@
     }
 
     state->mLast.set(this);
-    //LOGE("sgl2 vtx2 %x", glGetError());
+    rsc->checkError("ProgramVertex::setupGL2");
 }
 
 void ProgramVertex::addLight(const Light *l)
@@ -236,15 +236,37 @@
     mvp.vectorMultiply(v4out, v3in);
 }
 
+void ProgramVertex::initAddUserAttrib(const Element *e)
+{
+    rsAssert(e->getFieldCount());
+    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
+        const Element *ce = e->getField(ct);
+        if (ce->getFieldCount()) {
+            initAddUserAttrib(ce);
+        } else {
+            String8 tmp("ATTRIB_");
+            tmp.append(e->getFieldName(ct));
+            mAttribNames[mAttribCount].setTo(tmp.string());
+            mAttribCount++;
+        }
+    }
+}
+
 void ProgramVertex::init(Context *rsc)
 {
-    mAttribCount = 6;
-    mAttribNames[VertexArray::POSITION].setTo("attrib_Position");
-    mAttribNames[VertexArray::COLOR].setTo("attrib_Color");
-    mAttribNames[VertexArray::NORMAL].setTo("attrib_Normal");
-    mAttribNames[VertexArray::POINT_SIZE].setTo("attrib_PointSize");
-    mAttribNames[VertexArray::TEXTURE_0].setTo("attrib_T0");
-    mAttribNames[VertexArray::TEXTURE_1].setTo("attrib_T1");
+    if (mUserShader.size() > 0) {
+        mAttribCount = 0;
+        for (uint32_t ct=0; ct < mInputCount; ct++) {
+            initAddUserAttrib(mInputElements[ct].get());
+        }
+    } else {
+        mAttribCount = 5;
+        mAttribNames[0].setTo("ATTRIB_Position");
+        mAttribNames[1].setTo("ATTRIB_Color");
+        mAttribNames[2].setTo("ATTRIB_Normal");
+        mAttribNames[3].setTo("ATTRIB_PointSize");
+        mAttribNames[4].setTo("ATTRIB_Texture");
+    }
 
     mUniformCount = 2;
     mUniformNames[0].setTo("uni_MVP");
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 8c63d82..dcb988c 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -59,6 +59,9 @@
 
     // Hacks to create a program for now
     bool mTextureMatrixEnable;
+
+private:
+    void initAddUserAttrib(const Element *e);
 };
 
 
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 917f294..8a0ab71 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -738,9 +738,7 @@
 
     VertexArray va;
     va.setPosition(3, GL_FLOAT, 12, (uint32_t)&vtx);
-    va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex, 0);
-    //va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex, 1);
-    //
+    va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex);
     if (rsc->checkVersion2_0()) {
         va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 311e3f5..0d9863de 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -59,6 +59,7 @@
             glUseProgram(mEntries[ct].program);
             mCurrent = &mEntries[ct];
             //LOGV("ShaderCache hit, using %i", ct);
+            rsc->checkError("ShaderCache::lookup (hit)");
             return true;
         }
     }
@@ -91,12 +92,15 @@
         //LOGE("e1 %x", glGetError());
         glAttachShader(pgm, frag->getShaderID());
 
-        glBindAttribLocation(pgm, VertexArray::POSITION, "attrib_Position");
-        glBindAttribLocation(pgm, VertexArray::COLOR, "attrib_Color");
-        //glBindAttribLocation(pgm, VertexArray::NORMAL, "attrib_Normal");
-        //glBindAttribLocation(pgm, VertexArray::POINT_SIZE, "attrib_PointSize");
-        //glBindAttribLocation(pgm, VertexArray::TEXTURE_0, "attrib_T0");
-        //glBindAttribLocation(pgm, VertexArray::TEXTURE_1, "attrib_T1");
+        if (!vtx->isUserProgram()) {
+            glBindAttribLocation(pgm, VertexArray::POSITION, "ATTRIB_Position");
+            glBindAttribLocation(pgm, VertexArray::COLOR, "ATTRIB_Color");
+            glBindAttribLocation(pgm, VertexArray::NORMAL, "ATTRIB_Normal");
+            glBindAttribLocation(pgm, VertexArray::POINT_SIZE, "ATTRIB_PointSize");
+            glBindAttribLocation(pgm, VertexArray::TEXTURE, "ATTRIB_T0");
+        } else {
+
+        }
 
         //LOGE("e2 %x", glGetError());
         glLinkProgram(pgm);
@@ -119,7 +123,7 @@
         for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
             e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct));
             if (rsc->props.mLogShaders) {
-                LOGV("vtx A, %s = %d\n", vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]);
+                LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]);
             }
         }
         for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
@@ -139,6 +143,7 @@
     //LOGV("SC made program %i", e->program);
     glUseProgram(e->program);
     mEntryCount++;
+    rsc->checkError("ShaderCache::lookup (miss)");
     return true;
 }
 
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
index 5f5622d..a819c07 100644
--- a/libs/rs/rsSimpleMesh.cpp
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -55,18 +55,25 @@
         return;
     }
 
+    rsc->checkError("SimpleMesh::renderRange 1");
     VertexArray va;
-    for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-        mVertexBuffers[ct]->uploadCheck(rsc);
-        va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
-        mVertexTypes[ct]->enableGLVertexBuffer(&va);
-    }
     if (rsc->checkVersion2_0()) {
+        for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+            mVertexBuffers[ct]->uploadCheck(rsc);
+            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+            mVertexTypes[ct]->enableGLVertexBuffer2(&va);
+        }
         va.setupGL2(rsc, 0, &rsc->mShaderCache);
     } else {
+        for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+            mVertexBuffers[ct]->uploadCheck(rsc);
+            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+            mVertexTypes[ct]->enableGLVertexBuffer(&va);
+        }
         va.setupGL(rsc, 0);
     }
 
+    rsc->checkError("SimpleMesh::renderRange 2");
     if (mIndexType.get()) {
         mIndexBuffer->uploadCheck(rsc);
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index e7bcb08..d3b53d6 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -26,7 +26,6 @@
     mAllocLine = __LINE__;
     mLODs = 0;
     mLODCount = 0;
-    memset(&mGL, 0, sizeof(mGL));
     clear();
 }
 
@@ -133,18 +132,28 @@
 
 void Type::makeGLComponents()
 {
-    uint32_t texNum = 0;
-    memset(&mGL, 0, sizeof(mGL));
+    uint32_t userNum = 0;
 
     for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
         const Component &c = getElement()->getField(ct)->getComponent();
 
         switch(c.getKind()) {
+        case RS_KIND_USER:
+            mGL.mUser[userNum].size = c.getVectorSize();
+            mGL.mUser[userNum].offset = mElement->getFieldOffsetBytes(ct);
+            mGL.mUser[userNum].type = c.getGLType();
+            mGL.mUser[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+            mGL.mUser[userNum].name.setTo(getElement()->getFieldName(ct));
+            userNum ++;
+            break;
+
         case RS_KIND_POSITION:
             rsAssert(mGL.mVtx.size == 0);
             mGL.mVtx.size = c.getVectorSize();
             mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct);
             mGL.mVtx.type = c.getGLType();
+            mGL.mVtx.normalized = false;
+            mGL.mVtx.name.setTo("Position");
             break;
 
         case RS_KIND_COLOR:
@@ -152,6 +161,8 @@
             mGL.mColor.size = c.getVectorSize();
             mGL.mColor.offset = mElement->getFieldOffsetBytes(ct);
             mGL.mColor.type = c.getGLType();
+            mGL.mColor.normalized = c.getType() != RS_TYPE_FLOAT_32;
+            mGL.mColor.name.setTo("Color");
             break;
 
         case RS_KIND_NORMAL:
@@ -159,15 +170,17 @@
             mGL.mNorm.size = c.getVectorSize();
             mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct);
             mGL.mNorm.type = c.getGLType();
+            mGL.mNorm.normalized = false;
+            mGL.mNorm.name.setTo("Normal");
             break;
 
         case RS_KIND_TEXTURE:
-            if (mGL.mTex[texNum].size) {
-                texNum++;
-            }
-            mGL.mTex[texNum].size = c.getVectorSize();
-            mGL.mTex[texNum].offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mTex[texNum].type = c.getGLType();
+            rsAssert(mGL.mTex.size == 0);
+            mGL.mTex.size = c.getVectorSize();
+            mGL.mTex.offset = mElement->getFieldOffsetBytes(ct);
+            mGL.mTex.type = c.getGLType();
+            mGL.mTex.normalized = false;
+            mGL.mTex.name.setTo("Texture");
             break;
 
         case RS_KIND_POINT_SIZE:
@@ -175,6 +188,8 @@
             mGL.mPointSize.size = c.getVectorSize();
             mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct);
             mGL.mPointSize.type = c.getGLType();
+            mGL.mPointSize.normalized = false;
+            mGL.mPointSize.name.setTo("PointSize");
         break;
 
         default:
@@ -186,7 +201,7 @@
 void Type::enableGLVertexBuffer(VertexArray *va) const
 {
     // Note: We are only going to enable buffers and never disable them
-    // here.  The reasonis more than one Allocation may be used as a vertex
+    // here.  The reason is more than one Allocation may be used as a vertex
     // source.  So we cannot disable arrays that may have been in use by
     // another allocation.
 
@@ -211,14 +226,11 @@
                      mGL.mColor.offset);
     }
 
-    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
-        if (mGL.mTex[ct].size) {
-            va->setTexture(mGL.mTex[ct].size,
-                           mGL.mTex[ct].type,
-                           stride,
-                           mGL.mTex[ct].offset,
-                           ct);
-        }
+    if (mGL.mTex.size) {
+        va->setTexture(mGL.mTex.size,
+                       mGL.mTex.type,
+                       stride,
+                       mGL.mTex.offset);
     }
 
     if (mGL.mPointSize.size) {
@@ -229,6 +241,20 @@
 
 }
 
+void Type::enableGLVertexBuffer2(VertexArray *va) const
+{
+    // Do legacy buffers
+    enableGLVertexBuffer(va);
+
+    uint32_t stride = mElement->getSizeBytes();
+    for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
+        if (mGL.mUser[ct].size) {
+            va->setUser(mGL.mUser[ct], stride);
+        }
+    }
+}
+
+
 
 void Type::dumpLOGV(const char *prefix) const
 {
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index d261d58..4fa4933 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -18,6 +18,7 @@
 #define ANDROID_STRUCTURED_TYPE_H
 
 #include "rsElement.h"
+#include "rsVertexArray.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -68,6 +69,7 @@
     void compute();
 
     void enableGLVertexBuffer(class VertexArray *) const;
+    void enableGLVertexBuffer2(class VertexArray *) const;
 
     void dumpLOGV(const char *prefix) const;
 
@@ -108,18 +110,13 @@
     LOD *mLODs;
     uint32_t mLODCount;
 
-    struct VertexComponent_t {
-        uint32_t offset;
-        uint32_t type;
-        uint32_t size;
-        uint32_t stride;
-    };
     struct GLState_t {
-        VertexComponent_t mVtx;
-        VertexComponent_t mNorm;
-        VertexComponent_t mColor;
-        VertexComponent_t mTex[RS_MAX_TEXTURE];
-        VertexComponent_t mPointSize;
+        VertexArray::Attrib mUser[RS_MAX_ATTRIBS];
+        VertexArray::Attrib mVtx;
+        VertexArray::Attrib mNorm;
+        VertexArray::Attrib mColor;
+        VertexArray::Attrib mTex;
+        VertexArray::Attrib mPointSize;
     };
     GLState_t mGL;
     void makeGLComponents();
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index 2ba0ef9..7a8e054 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -25,8 +25,8 @@
 
 VertexArray::VertexArray()
 {
-    memset(mAttribs, 0, sizeof(mAttribs));
     mActiveBuffer = 0;
+    mUserCount = 0;
 }
 
 VertexArray::~VertexArray()
@@ -36,13 +36,43 @@
 
 void VertexArray::clearAll()
 {
-    memset(mAttribs, 0, sizeof(mAttribs));
+    for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
+        mAttribs[ct].clear();
+    }
     mActiveBuffer = 0;
+    mUserCount = 0;
+}
+
+VertexArray::Attrib::Attrib()
+{
+    clear();
+}
+
+void VertexArray::Attrib::set(const Attrib &a)
+{
+    buffer = a.buffer;
+    offset = a.offset;
+    type = a.type;
+    size = a.size;
+    stride = a.stride;
+    normalized = a.normalized;
+    name.setTo(a.name);
+}
+
+void VertexArray::Attrib::clear()
+{
+    buffer = 0;
+    offset = 0;
+    type = 0;
+    size = 0;
+    stride = 0;
+    normalized = false;
+    name.setTo("");
 }
 
 void VertexArray::clear(AttribName n)
 {
-    mAttribs[n].size = 0;
+    mAttribs[n].clear();
 }
 
 void VertexArray::setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
@@ -85,18 +115,27 @@
     mAttribs[POINT_SIZE].normalized = false;
 }
 
-void VertexArray::setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset, uint32_t num)
+void VertexArray::setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
 {
-    mAttribs[TEXTURE_0 + num].buffer = mActiveBuffer;
-    mAttribs[TEXTURE_0 + num].type = type;
-    mAttribs[TEXTURE_0 + num].size = size;
-    mAttribs[TEXTURE_0 + num].offset = offset;
-    mAttribs[TEXTURE_0 + num].stride = stride;
-    mAttribs[TEXTURE_0 + num].normalized = false;
+    mAttribs[TEXTURE].buffer = mActiveBuffer;
+    mAttribs[TEXTURE].type = type;
+    mAttribs[TEXTURE].size = size;
+    mAttribs[TEXTURE].offset = offset;
+    mAttribs[TEXTURE].stride = stride;
+    mAttribs[TEXTURE].normalized = false;
 }
 
-void VertexArray::logAttrib(uint32_t idx) const {
-    LOGE("va %i: buf=%i  size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x", idx,
+void VertexArray::setUser(const Attrib &a, uint32_t stride)
+{
+    mAttribs[mUserCount].set(a);
+    mAttribs[mUserCount].buffer = mActiveBuffer;
+    mAttribs[mUserCount].stride = stride;
+    mUserCount ++;
+}
+
+void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+    LOGE("va %i: slot=%i name=%s buf=%i  size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x", idx, slot,
+         mAttribs[idx].name.string(),
          mAttribs[idx].buffer,
          mAttribs[idx].size,
          mAttribs[idx].type,
@@ -143,21 +182,18 @@
         glDisableClientState(GL_COLOR_ARRAY);
     }
 
-    for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
-        glClientActiveTexture(GL_TEXTURE0 + ct);
-        if (mAttribs[TEXTURE_0 + ct].size) {
-            //logAttrib(TEXTURE_0 + ct);
-            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[TEXTURE_0 + ct].buffer);
-            glTexCoordPointer(mAttribs[TEXTURE_0 + ct].size,
-                              mAttribs[TEXTURE_0 + ct].type,
-                              mAttribs[TEXTURE_0 + ct].stride,
-                              (void *)mAttribs[TEXTURE_0 + ct].offset);
-        } else {
-            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-        }
-    }
     glClientActiveTexture(GL_TEXTURE0);
+    if (mAttribs[TEXTURE].size) {
+        //logAttrib(TEXTURE);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[TEXTURE].buffer);
+        glTexCoordPointer(mAttribs[TEXTURE].size,
+                          mAttribs[TEXTURE].type,
+                          mAttribs[TEXTURE].stride,
+                          (void *)mAttribs[TEXTURE].offset);
+    } else {
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    }
 
     if (mAttribs[POINT_SIZE].size) {
         //logAttrib(POINT_SIZE);
@@ -178,12 +214,12 @@
         glDisableVertexAttribArray(ct);
     }
 
-    for (int ct=0; ct < _LAST; ct++) {
+    for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
         if (mAttribs[ct].size) {
-            //logAttrib(ct);
+            //logAttrib(ct, sc->vtxAttribSlot(ct));
+            rsAssert(sc->vtxAttribSlot(ct) >= 0);
             glEnableVertexAttribArray(sc->vtxAttribSlot(ct));
             glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-            //LOGV("attp %i %i", ct, sc->vtxAttribSlot(ct));
 
             glVertexAttribPointer(sc->vtxAttribSlot(ct),
                                   mAttribs[ct].size,
@@ -191,9 +227,6 @@
                                   mAttribs[ct].normalized,
                                   mAttribs[ct].stride,
                                   (void *)mAttribs[ct].offset);
-        } else {
-            //glDisableVertexAttribArray(ct);
-            rsAssert(ct);
         }
     }
     rsc->checkError("VertexArray::setupGL2");
@@ -201,6 +234,5 @@
 ////////////////////////////////////////////
 
 void VertexArrayState::init(Context *) {
-    memset(this, 0, sizeof(this));
 }
 
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/rsVertexArray.h
index f97813f..998e9ad 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/rsVertexArray.h
@@ -38,19 +38,24 @@
         COLOR,
         NORMAL,
         POINT_SIZE,
-        TEXTURE_0,
-        TEXTURE_1,
+        TEXTURE,
         _LAST
     };
 
-    typedef struct {
+    class Attrib {
+    public:
         uint32_t buffer;
         uint32_t offset;
         uint32_t type;
         uint32_t size;
         uint32_t stride;
         bool normalized;
-    } Attrib;
+        String8 name;
+
+        Attrib();
+        void set(const Attrib &);
+        void clear();
+    };
 
 
     void clearAll();
@@ -58,19 +63,21 @@
 
     void setActiveBuffer(uint32_t id) {mActiveBuffer = id;}
 
+    void setUser(const Attrib &, uint32_t stride);
     void setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
     void setColor(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
     void setNormal(uint32_t type, uint32_t stride, uint32_t offset);
     void setPointSize(uint32_t type, uint32_t stride, uint32_t offset);
-    void setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset, uint32_t num);
+    void setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
 
     void setupGL(const Context *rsc, class VertexArrayState *) const;
     void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
-    void logAttrib(uint32_t idx) const;
+    void logAttrib(uint32_t idx, uint32_t slot) const;
 
 protected:
     uint32_t mActiveBuffer;
-    Attrib mAttribs[_LAST];
+    uint32_t mUserCount;
+    Attrib mAttribs[RS_MAX_ATTRIBS];
 };
 
 
@@ -78,7 +85,7 @@
 public:
     void init(Context *);
 
-    VertexArray::Attrib mAttribs[VertexArray::_LAST];
+    //VertexArray::Attrib mAttribs[VertexArray::_LAST];
 };
 
 
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 2ce1273..c325b1b 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -45,10 +45,7 @@
 public final class Geocoder {
     private static final String TAG = "Geocoder";
 
-    private String mLanguage;
-    private String mCountry;
-    private String mVariant;
-    private String mAppName;
+    private GeocoderParams mParams;
     private ILocationManager mService;
 
     /**
@@ -64,11 +61,7 @@
         if (locale == null) {
             throw new NullPointerException("locale == null");
         }
-        mLanguage = locale.getLanguage();
-        mCountry = locale.getCountry();
-        mVariant = locale.getVariant();
-        mAppName = context.getPackageName();
-
+        mParams = new GeocoderParams(context, locale);
         IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
         mService = ILocationManager.Stub.asInterface(b);
     }
@@ -119,7 +112,7 @@
         try {
             List<Address> results = new ArrayList<Address>();
             String ex =  mService.getFromLocation(latitude, longitude, maxResults,
-                mLanguage, mCountry, mVariant, mAppName, results);
+                mParams, results);
             if (ex != null) {
                 throw new IOException(ex);
             } else {
@@ -161,7 +154,7 @@
         try {
             List<Address> results = new ArrayList<Address>();
             String ex = mService.getFromLocationName(locationName,
-                0, 0, 0, 0, maxResults, mLanguage, mCountry, mVariant, mAppName, results);
+                0, 0, 0, 0, maxResults, mParams, results);
             if (ex != null) {
                 throw new IOException(ex);
             } else {
@@ -234,7 +227,7 @@
             ArrayList<Address> result = new ArrayList<Address>();
             String ex =  mService.getFromLocationName(locationName,
                 lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                maxResults, mLanguage, mCountry, mVariant, mAppName, result);
+                maxResults, mParams, result);
             if (ex != null) {
                 throw new IOException(ex);
             } else {
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/GeocoderParams.aidl
new file mode 100644
index 0000000..2484e20
--- /dev/null
+++ b/location/java/android/location/GeocoderParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.location;
+
+parcelable GeocoderParams;
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
new file mode 100644
index 0000000..8b8e63b
--- /dev/null
+++ b/location/java/android/location/GeocoderParams.java
@@ -0,0 +1,92 @@
+/*
+ * 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.location;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ * This class contains extra parameters to pass to an IGeocodeProvider
+ * implementation from the Geocoder class.  Currently this contains the
+ * language, country and variant information from the Geocoder's locale
+ * as well as the Geocoder client's package name for geocoder server
+ * logging.  This information is kept in a separate class to allow for
+ * future expansion of the IGeocodeProvider interface.
+ */
+public class GeocoderParams implements Parcelable {
+    private Locale mLocale;
+    private String mPackageName;
+
+    // used only for parcelling
+    private GeocoderParams() {
+    }
+
+    /**
+     * This object is only constructed by the Geocoder class
+     *
+     * @hide
+     */
+    public GeocoderParams(Context context, Locale locale) {
+        mLocale = locale;
+        mPackageName = context.getPackageName();
+    }
+
+    /**
+     * returns the Geocoder's locale
+     */
+    public Locale getLocale() {
+        return mLocale;
+    }
+
+    /**
+     * returns the package name of the Geocoder's client
+     */
+    public String getClientPackage() {
+        return mPackageName;
+    }
+
+    public static final Parcelable.Creator<GeocoderParams> CREATOR =
+        new Parcelable.Creator<GeocoderParams>() {
+        public GeocoderParams createFromParcel(Parcel in) {
+            GeocoderParams gp = new GeocoderParams();
+            String language = in.readString();
+            String country = in.readString();
+            String variant = in.readString();
+            gp.mLocale = new Locale(language, country, variant);
+            gp.mPackageName = in.readString();
+            return gp;
+        }
+
+        public GeocoderParams[] newArray(int size) {
+            return new GeocoderParams[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mLocale.getLanguage());
+        parcel.writeString(mLocale.getCountry());
+        parcel.writeString(mLocale.getVariant());
+        parcel.writeString(mPackageName);
+    }
+}
diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl
index e79e8d2..aaa70c7 100644
--- a/location/java/android/location/IGeocodeProvider.aidl
+++ b/location/java/android/location/IGeocodeProvider.aidl
@@ -17,6 +17,7 @@
 package android.location;
 
 import android.location.Address;
+import android.location.GeocoderParams;
 
 /**
  * An interface for location providers implementing the Geocoder services.
@@ -26,10 +27,10 @@
 interface IGeocodeProvider {
 
     String getFromLocation(double latitude, double longitude, int maxResults,
-        String language, String country, String variant, String appName, out List<Address> addrs);
+        in GeocoderParams params, out List<Address> addrs);
 
     String getFromLocationName(String locationName,
         double lowerLeftLatitude, double lowerLeftLongitude,
         double upperRightLatitude, double upperRightLongitude, int maxResults,
-        String language, String country, String variant, String appName, out List<Address> addrs);
+        in GeocoderParams params, out List<Address> addrs);
 }
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index b6c59d6..1fac07c 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.location.Address;
+import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
 import android.location.IGpsStatusListener;
 import android.location.ILocationListener;
@@ -63,11 +64,11 @@
     void reportLocation(in Location location);
 
     String getFromLocation(double latitude, double longitude, int maxResults,
-        String language, String country, String variant, String appName, out List<Address> addrs);
+        in GeocoderParams params, out List<Address> addrs);
     String getFromLocationName(String locationName,
         double lowerLeftLatitude, double lowerLeftLongitude,
         double upperRightLatitude, double upperRightLongitude, int maxResults,
-        String language, String country, String variant, String appName, out List<Address> addrs);
+        in GeocoderParams params, out List<Address> addrs);
 
     void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
         boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 94ced22..cbe10d9 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -105,6 +105,48 @@
      */
     public static final String KEY_LOCATION_CHANGED = "location";
 
+    public interface GeocodeProvider {
+        String getFromLocation(double latitude, double longitude, int maxResults,
+            GeocoderParams params, List<Address> addrs);
+
+        String getFromLocationName(String locationName,
+            double lowerLeftLatitude, double lowerLeftLongitude,
+            double upperRightLatitude, double upperRightLongitude, int maxResults,
+            GeocoderParams params, List<Address> addrs);
+    }
+
+    private static final class GeocodeProviderProxy extends IGeocodeProvider.Stub {
+        private GeocodeProvider mProvider;
+
+        GeocodeProviderProxy(GeocodeProvider provider) {
+            mProvider = provider;
+        }
+
+        /**
+         * This method is overridden to implement the
+         * {@link Geocoder#getFromLocation(double, double, int)} method.
+         * Classes implementing this method should not hold a reference to the params parameter.
+         */
+        public String getFromLocation(double latitude, double longitude, int maxResults,
+                GeocoderParams params, List<Address> addrs) {
+            return mProvider.getFromLocation(latitude, longitude, maxResults, params, addrs);
+        }
+
+        /**
+         * This method is overridden to implement the
+         * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
+         * Classes implementing this method should not hold a reference to the params parameter.
+         */
+        public String getFromLocationName(String locationName,
+                double lowerLeftLatitude, double lowerLeftLongitude,
+                double upperRightLatitude, double upperRightLongitude, int maxResults,
+                GeocoderParams params, List<Address> addrs) {
+            return mProvider.getFromLocationName(locationName, lowerLeftLatitude,
+                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+                    maxResults, params, addrs);
+        }
+    }
+
     // Map from LocationListeners to their associated ListenerTransport objects
     private HashMap<LocationListener,ListenerTransport> mListeners =
         new HashMap<LocationListener,ListenerTransport>();
@@ -1388,9 +1430,9 @@
      *
      * {@hide}
      */
-    public boolean installGeocodeProvider(IGeocodeProvider provider) {
+    public boolean installGeocodeProvider(GeocodeProvider provider) {
         try {
-            mService.installGeocodeProvider(provider);
+            mService.installGeocodeProvider(new GeocodeProviderProxy(provider));
             return true;
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in setGeocodeProvider: ", e);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8e71700..af57a4c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -721,9 +721,13 @@
     }
 
     if (!strncasecmp(url, "http://", 7)) {
-        // For now, we're going to use PV for http-based playback,
-        // until we can clear up a few more issues.
-        return PV_PLAYER;
+        char value[PROPERTY_VALUE_MAX];
+        if (!property_get("media.stagefright.enable-http", value, NULL)
+            || (strcmp(value, "1") && strcasecmp(value, "true"))) {
+            // For now, we're going to use PV for http-based playback
+            // by default until we can clear up a few more issues.
+            return PV_PLAYER;
+        }
     }
 
     return getDefaultPlayerType();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 9e388f9..6bcdfba 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -26,11 +26,13 @@
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
+
 namespace android {
 
 struct AwesomeEvent : public TimedEventQueue::Event {
@@ -516,10 +518,19 @@
         return UNKNOWN_ERROR;
     }
 
-    mAudioSource = OMXCodec::Create(
-            mClient.interface(), source->getFormat(),
-            false, // createEncoder
-            source);
+    sp<MetaData> meta = source->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+        mAudioSource = source;
+    } else {
+        mAudioSource = OMXCodec::Create(
+                mClient.interface(), source->getFormat(),
+                false, // createEncoder
+                source);
+    }
 
     if (mAudioSource != NULL) {
         int64_t durationUs;
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 5536801..7e8bbc6 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -24,6 +24,69 @@
 
 namespace android {
 
+// Given a connected HTTPStream, determine if the given path redirects
+// somewhere else, if so, disconnect the stream, update host path and port
+// accordingly and return true, otherwise return false and leave the stream
+// connected.
+static bool PerformRedirectIfNecessary(
+        HTTPStream *http, string *host, string *path, int *port) {
+    String8 request;
+    request.append("HEAD ");
+    request.append(path->c_str());
+    request.append(" HTTP/1.1\r\n");
+    request.append("Host: ");
+    request.append(host->c_str());
+    request.append("\r\n\r\n");
+
+    status_t err = http->send(request.string());
+
+    int http_status;
+    if (err == OK) {
+        err = http->receive_header(&http_status);
+    }
+
+    if (err != OK) {
+        return false;
+    }
+
+    if (http_status != 301 && http_status != 302) {
+        return false;
+    }
+
+    string location;
+    CHECK(http->find_header_value("Location", &location));
+
+    CHECK(string(location, 0, 7) == "http://");
+    location.erase(0, 7);
+    string::size_type slashPos = location.find('/');
+    if (slashPos == string::npos) {
+        slashPos = location.size();
+        location += '/';
+    }
+
+    http->disconnect();
+
+    LOGI("Redirecting to %s\n", location.c_str());
+
+    *host = string(location, 0, slashPos);
+
+    string::size_type colonPos = host->find(':');
+    if (colonPos != string::npos) {
+        const char *start = host->c_str() + colonPos + 1;
+        char *end;
+        long tmp = strtol(start, &end, 10);
+        CHECK(end > start && (*end == '\0'));
+
+        *port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
+    } else {
+        *port = 80;
+    }
+
+    *path = string(location, slashPos);
+
+    return true;
+}
+
 HTTPDataSource::HTTPDataSource(const char *uri)
     : mHttp(new HTTPStream),
       mHost(NULL),
@@ -63,22 +126,44 @@
     LOGI("Connecting to host '%s', port %d, path '%s'",
          host.c_str(), port, path.c_str());
 
+    do {
+        mInitCheck = mHttp->connect(host.c_str(), port);
+
+        if (mInitCheck != OK) {
+            return;
+        }
+    } while (PerformRedirectIfNecessary(mHttp, &host, &path, &port));
+
     mHost = strdup(host.c_str());
     mPort = port;
     mPath = strdup(path.c_str());
-
-    mInitCheck = mHttp->connect(mHost, mPort);
 }
 
-HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
+HTTPDataSource::HTTPDataSource(const char *_host, int port, const char *_path)
     : mHttp(new HTTPStream),
-      mHost(strdup(host)),
-      mPort(port),
-      mPath(strdup(path)),
+      mHost(NULL),
+      mPort(0),
+      mPath(NULL),
       mBuffer(malloc(kBufferSize)),
       mBufferLength(0),
       mBufferOffset(0) {
-    mInitCheck = mHttp->connect(mHost, mPort);
+    string host = _host;
+    string path = _path;
+
+    LOGI("Connecting to host '%s', port %d, path '%s'",
+         host.c_str(), port, path.c_str());
+
+    do {
+        mInitCheck = mHttp->connect(host.c_str(), port);
+
+        if (mInitCheck != OK) {
+            return;
+        }
+    } while (PerformRedirectIfNecessary(mHttp, &host, &path, &port));
+
+    mHost = strdup(host.c_str());
+    mPort = port;
+    mPath = strdup(path.c_str());
 }
 
 status_t HTTPDataSource::initCheck() const {
@@ -91,8 +176,15 @@
     free(mBuffer);
     mBuffer = NULL;
 
-    free(mPath);
-    mPath = NULL;
+    if (mPath) {
+        free(mPath);
+        mPath = NULL;
+    }
+
+    if (mHost) {
+        free(mHost);
+        mHost = NULL;
+    }
 
     delete mHttp;
     mHttp = NULL;
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 92059c5..ff51e88 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -70,7 +70,8 @@
     uint32_t type;
     const void *data;
     size_t size;
-    if (mSource->getFormat()->findData(kKeyESDS, &type, &data, &size)) {
+    sp<MetaData> meta = mSource->getFormat();
+    if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
         CHECK_EQ(esds.InitCheck(), OK);
 
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index 22e6188..229e933 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -90,7 +90,8 @@
     uint32_t type;
     const void *data;
     size_t size;
-    if (mSource->getFormat()->findData(kKeyAVCC, &type, &data, &size)) {
+    sp<MetaData> meta = mSource->getFormat();
+    if (meta->findData(kKeyAVCC, &type, &data, &size)) {
         // Parse the AVCDecoderConfigurationRecord
 
         const uint8_t *ptr = (const uint8_t *)data;
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
index ec3ad47..40009f8 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
@@ -87,7 +87,8 @@
     CHECK(!mStarted);
 
     const char *mime = NULL;
-    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+    sp<MetaData> meta = mSource->getFormat();
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
 
     MP4DecodingMode mode;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
@@ -102,7 +103,7 @@
     size_t size = 0;
     uint8_t *vol_data[1] = {0};
     int32_t vol_size = 0;
-    if (mSource->getFormat()->findData(kKeyESDS, &type, &data, &size)) {
+    if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const uint8_t *)data, size);
         CHECK_EQ(esds.InitCheck(), OK);
 
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
index bd6204b..8b2c36c 100644
--- a/media/libstagefright/string.cpp
+++ b/media/libstagefright/string.cpp
@@ -16,6 +16,8 @@
 
 #include "include/stagefright_string.h"
 
+#include <media/stagefright/MediaDebug.h>
+
 namespace android {
 
 // static
@@ -28,8 +30,15 @@
     : mString(s, length) {
 }
 
-string::string(const string &from, size_type start, size_type length)
-    : mString(from.c_str() + start, length) {
+string::string(const string &from, size_type start, size_type length) {
+    CHECK(start <= from.size());
+    if (length == npos) {
+        length = from.size() - start;
+    } else {
+        CHECK(start + length <= from.size());
+    }
+
+    mString.setTo(from.c_str() + start, length);
 }
 
 string::string(const char *s)
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index 81247df..384966c 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index 4029fa1..f1bd31d 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
index e73c249..995a5d7 100644
--- a/opengl/tests/gldual/Android.mk
+++ b/opengl/tests/gldual/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 724e988..bf4ab1b 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/packages/TtsService/Android.mk b/packages/TtsService/Android.mk
index 2737fb438..5eb6b9c 100644
--- a/packages/TtsService/Android.mk
+++ b/packages/TtsService/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files) \
 
diff --git a/packages/VpnServices/Android.mk b/packages/VpnServices/Android.mk
index eb27ed5..6cdf674 100644
--- a/packages/VpnServices/Android.mk
+++ b/packages/VpnServices/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/preloaded-classes b/preloaded-classes
index c50b36e..ddcecc9 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -698,7 +698,6 @@
 com.ibm.icu4jni.text.DecimalFormat
 com.ibm.icu4jni.text.DecimalFormatSymbols
 com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
-com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatSymbol
 com.ibm.icu4jni.text.RuleBasedCollator
 com.ibm.icu4jni.util.Resources$DefaultTimeZones
 dalvik.system.DexFile
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 84f0068..4279e00 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -23,12 +23,11 @@
 import android.os.Build;
 import android.os.DropBoxManager;
 import android.os.FileUtils;
+import android.os.RecoverySystem;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Log;
 
-import com.android.internal.os.RecoverySystem;
-
 import java.io.File;
 import java.io.IOException;
 
diff --git a/services/java/com/android/server/FallbackCheckinService.java b/services/java/com/android/server/FallbackCheckinService.java
index 1e5bc09..fc0ab69 100644
--- a/services/java/com/android/server/FallbackCheckinService.java
+++ b/services/java/com/android/server/FallbackCheckinService.java
@@ -21,11 +21,11 @@
 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.android.internal.os.RecoverySystem;
 import com.google.android.net.ParentalControlState;
 
 /**
@@ -50,7 +50,7 @@
 
         // Save the android ID so the new system can get it erased.
         try {
-            RecoverySystem.rebootAndWipe();
+            RecoverySystem.rebootWipeUserData(mContext);
         } catch (IOException e) {
             Log.e(TAG, "Reboot for masterClear() failed", e);
         }
@@ -67,7 +67,7 @@
 
         // Save the android ID so the new system can get it erased.
         try {
-            RecoverySystem.rebootAndToggleEFS(efsEnabled);
+            RecoverySystem.rebootToggleEFS(mContext, efsEnabled);
         } catch (IOException e) {
             Log.e(TAG, "Reboot for toggle EFS failed", e);
         }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index c17a3bc..406897d 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -37,6 +37,7 @@
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.location.Address;
+import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -1655,11 +1656,11 @@
     // Geocoder
 
     public String getFromLocation(double latitude, double longitude, int maxResults,
-            String language, String country, String variant, String appName, List<Address> addrs) {
+            GeocoderParams params, List<Address> addrs) {
         if (mGeocodeProvider != null) {
             try {
-                return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
-                        variant, appName,  addrs);
+                return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
+                        params, addrs);
             } catch (RemoteException e) {
                 Log.e(TAG, "getFromLocation failed", e);
                 mGeocodeProvider = null;
@@ -1672,13 +1673,13 @@
     public String getFromLocationName(String locationName,
             double lowerLeftLatitude, double lowerLeftLongitude,
             double upperRightLatitude, double upperRightLongitude, int maxResults,
-            String language, String country, String variant, String appName, List<Address> addrs) {
+            GeocoderParams params, List<Address> addrs) {
 
         if (mGeocodeProvider != null) {
             try {
                 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
                         lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                        maxResults, language, country, variant, appName, addrs);
+                        maxResults, params, addrs);
             } catch (RemoteException e) {
                 Log.e(TAG, "getFromLocationName failed", e);
                 mGeocodeProvider = null;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bf436b6..7f12b6d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1194,7 +1194,7 @@
                     int uid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    uninstallPackageLocked(pkg, uid, restart);
+                    forceStopPackageLocked(pkg, uid, restart);
                 }
             } break;
             }
@@ -2734,8 +2734,7 @@
                 // Whoops, need to restart this activity!
                 next.state = lastState;
                 mResumedActivity = lastResumedActivity;
-                if (Config.LOGD) Log.d(TAG,
-                        "Restarting because process died: " + next);
+                Log.i(TAG, "Restarting because process died: " + next);
                 if (!next.hasBeenLaunched) {
                     next.hasBeenLaunched = true;
                 } else {
@@ -4293,7 +4292,9 @@
         
         cleanUpActivityLocked(r, false);
 
-        if (r.app != null) {
+        final boolean hadApp = r.app != null;
+        
+        if (hadApp) {
             if (removeFromApp) {
                 int idx = r.app.activities.indexOf(r);
                 if (idx >= 0) {
@@ -4350,16 +4351,14 @@
 
         r.configChangeFlags = 0;
         
-        if (!mLRUActivities.remove(r)) {
+        if (!mLRUActivities.remove(r) && hadApp) {
             Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
         }
         
         return removedFromHistory;
     }
 
-    private static void removeHistoryRecordsForAppLocked(ArrayList list,
-                                                         ProcessRecord app)
-    {
+    private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
         int i = list.size();
         if (localLOGV) Log.v(
             TAG, "Removing app " + app + " from list " + list
@@ -4550,7 +4549,7 @@
                     scheduleAppGcsLocked();
                 }
             }
-        } else if (Config.LOGD) {
+        } else if (DEBUG_PROCESSES) {
             Log.d(TAG, "Received spurious death notification for thread "
                     + thread.asBinder());
         }
@@ -4852,7 +4851,7 @@
                         android.Manifest.permission.CLEAR_APP_USER_DATA,
                         pid, uid, -1)
                         == PackageManager.PERMISSION_GRANTED) {
-                    restartPackageLocked(packageName, pkgUid);
+                    forceStopPackageLocked(packageName, pkgUid);
                 } else {
                     throw new SecurityException(pid+" does not have permission:"+
                             android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
@@ -4877,13 +4876,15 @@
         return true;
     }
 
-    public void restartPackage(final String packageName) {
-        if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
-                != PackageManager.PERMISSION_GRANTED) {
-            String msg = "Permission Denial: restartPackage() from pid="
+    public void killBackgroundProcesses(final String packageName) {
+        if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+                != PackageManager.PERMISSION_GRANTED &&
+                checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
+                        != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: killBackgroundProcesses() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + android.Manifest.permission.RESTART_PACKAGES;
+                    + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
             Log.w(TAG, msg);
             throw new SecurityException(msg);
         }
@@ -4901,7 +4902,39 @@
                     Log.w(TAG, "Invalid packageName: " + packageName);
                     return;
                 }
-                restartPackageLocked(packageName, pkgUid);
+                killPackageProcessesLocked(packageName, pkgUid,
+                        SECONDARY_SERVER_ADJ, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
+    public void forceStopPackage(final String packageName) {
+        if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: forceStopPackage() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+            Log.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            int pkgUid = -1;
+            synchronized(this) {
+                try {
+                    pkgUid = pm.getPackageUid(packageName);
+                } catch (RemoteException e) {
+                }
+                if (pkgUid == -1) {
+                    Log.w(TAG, "Invalid packageName: " + packageName);
+                    return;
+                }
+                forceStopPackageLocked(packageName, pkgUid);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -5011,8 +5044,8 @@
         }
     }
 
-    private void restartPackageLocked(final String packageName, int uid) {
-        uninstallPackageLocked(packageName, uid, false);
+    private void forceStopPackageLocked(final String packageName, int uid) {
+        forceStopPackageLocked(packageName, uid, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         intent.putExtra(Intent.EXTRA_UID, uid);
@@ -5021,13 +5054,41 @@
                 false, false, MY_PID, Process.SYSTEM_UID);
     }
     
-    private final void uninstallPackageLocked(String name, int uid,
-            boolean callerWillRestart) {
-        if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
+    private final void killPackageProcessesLocked(String packageName, int uid,
+            int minOomAdj, boolean callerWillRestart) {
+        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
 
+        // Remove all processes this package may have touched: all with the
+        // same UID (except for the system or root user), and all whose name
+        // matches the package name.
+        final String procNamePrefix = packageName + ":";
+        for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+            final int NA = apps.size();
+            for (int ia=0; ia<NA; ia++) {
+                ProcessRecord app = apps.valueAt(ia);
+                if (app.removed) {
+                    procs.add(app);
+                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
+                        || app.processName.equals(packageName)
+                        || app.processName.startsWith(procNamePrefix)) {
+                    if (app.setAdj >= minOomAdj) {
+                        app.removed = true;
+                        procs.add(app);
+                    }
+                }
+            }
+        }
+        
+        int N = procs.size();
+        for (int i=0; i<N; i++) {
+            removeProcessLocked(procs.get(i), callerWillRestart);
+        }
+    }
+    
+    private final void forceStopPackageLocked(String name, int uid,
+            boolean callerWillRestart) {
         int i, N;
 
-        final String procNamePrefix = name + ":";
         if (uid < 0) {
             try {
                 uid = ActivityThread.getPackageManager().getPackageUid(name);
@@ -5035,6 +5096,8 @@
             }
         }
 
+        Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
+
         Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
         while (badApps.hasNext()) {
             SparseArray<Long> ba = badApps.next();
@@ -5043,37 +5106,12 @@
             }
         }
 
-        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
-
-        // Remove all processes this package may have touched: all with the
-        // same UID (except for the system or root user), and all whose name
-        // matches the package name.
-        for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
-            final int NA = apps.size();
-            for (int ia=0; ia<NA; ia++) {
-                ProcessRecord app = apps.valueAt(ia);
-                if (app.removed) {
-                    procs.add(app);
-                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                        || app.processName.equals(name)
-                        || app.processName.startsWith(procNamePrefix)) {
-                    app.removed = true;
-                    procs.add(app);
-                }
-            }
-        }
-
-        N = procs.size();
-        for (i=0; i<N; i++) {
-            removeProcessLocked(procs.get(i), callerWillRestart);
-        }
+        killPackageProcessesLocked(name, uid, -100, callerWillRestart);
         
         for (i=mHistory.size()-1; i>=0; i--) {
             HistoryRecord r = (HistoryRecord)mHistory.get(i);
             if (r.packageName.equals(name)) {
-                if (Config.LOGD) Log.d(
-                    TAG, "  Force finishing activity "
-                    + r.intent.getComponent().flattenToShortString());
+                Log.i(TAG, "  Force finishing activity " + r);
                 if (r.app != null) {
                     r.app.removed = true;
                 }
@@ -5085,6 +5123,7 @@
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
         for (ServiceRecord service : mServices.values()) {
             if (service.packageName.equals(name)) {
+                Log.i(TAG, "  Force stopping service " + service);
                 if (service.app != null) {
                     service.app.removed = true;
                 }
@@ -5104,7 +5143,7 @@
     private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
         final String name = app.processName;
         final int uid = app.info.uid;
-        if (Config.LOGD) Log.d(
+        if (DEBUG_PROCESSES) Log.d(
             TAG, "Force removing process " + app + " (" + name
             + "/" + uid + ")");
 
@@ -7861,7 +7900,7 @@
 
         synchronized(this) {
             int count = mHistory.size();
-            if (Config.LOGD) Log.d(
+            if (DEBUG_SWITCH) Log.d(
                 TAG, "Performing unhandledBack(): stack size = " + count);
             if (count > 1) {
                 final long origId = Binder.clearCallingIdentity();
@@ -8062,7 +8101,7 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                uninstallPackageLocked(packageName, -1, false);
+                forceStopPackageLocked(packageName, -1, false);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -8686,8 +8725,7 @@
             for (int i=mHistory.size()-1; i>=0; i--) {
                 HistoryRecord r = (HistoryRecord)mHistory.get(i);
                 if (r.app == app) {
-                    if (Config.LOGD) Log.d(
-                        TAG, "  Force finishing activity "
+                    Log.w(TAG, "  Force finishing activity "
                         + r.intent.getComponent().flattenToShortString());
                     finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
                 }
@@ -11922,7 +11960,7 @@
                     String ssp;
                     if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                         if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
-                            uninstallPackageLocked(ssp,
+                            forceStopPackageLocked(ssp,
                                     intent.getIntExtra(Intent.EXTRA_UID, -1), false);
                             AttributeCache ac = AttributeCache.instance();
                             if (ac != null) {
@@ -12890,7 +12928,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            uninstallPackageLocked(ii.targetPackage, -1, true);
+            forceStopPackageLocked(ii.targetPackage, -1, true);
             ProcessRecord app = addAppLocked(ai);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12945,7 +12983,7 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        uninstallPackageLocked(app.processName, -1, false);
+        forceStopPackageLocked(app.processName, -1, false);
     }
 
     public void finishInstrumentation(IApplicationThread target,
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index cf06173..a01bc09 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -389,31 +389,39 @@
             }
             result = SetupResult.ERR_Stale;
         } else {
-            cid = Integer.parseInt(response[0]);
-            if (response.length > 2) {
+//            log("onSetupConnectionCompleted received " + response.length + " response strings:");
+//            for (int i = 0; i < response.length; i++) {
+//                log("  response[" + i + "]='" + response[i] + "'");
+//            }
+            if (response.length >= 2) {
+                cid = Integer.parseInt(response[0]);
                 interfaceName = response[1];
-                ipAddress = response[2];
-                String prefix = "net." + interfaceName + ".";
-                gatewayAddress = SystemProperties.get(prefix + "gw");
-                dnsServers[0] = SystemProperties.get(prefix + "dns1");
-                dnsServers[1] = SystemProperties.get(prefix + "dns2");
-                if (DBG) {
-                    log("interface=" + interfaceName + " ipAddress=" + ipAddress
-                        + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
-                        + " DNS2=" + dnsServers[1]);
-                }
+                if (response.length > 2) {
+                    ipAddress = response[2];
+                    String prefix = "net." + interfaceName + ".";
+                    gatewayAddress = SystemProperties.get(prefix + "gw");
+                    dnsServers[0] = SystemProperties.get(prefix + "dns1");
+                    dnsServers[1] = SystemProperties.get(prefix + "dns2");
+                    if (DBG) {
+                        log("interface=" + interfaceName + " ipAddress=" + ipAddress
+                            + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+                            + " DNS2=" + dnsServers[1]);
+                    }
 
-                if (isDnsOk(dnsServers)) {
-                    result = SetupResult.SUCCESS;
+                    if (isDnsOk(dnsServers)) {
+                        result = SetupResult.SUCCESS;
+                    } else {
+                        result = SetupResult.ERR_BadDns;
+                    }
                 } else {
-                    result = SetupResult.ERR_BadDns;
+                    result = SetupResult.SUCCESS;
                 }
             } else {
                 result = SetupResult.ERR_Other;
             }
         }
 
-        if (DBG) log("DataConnection setup result=" + result + " on cid = " + cid);
+        if (DBG) log("DataConnection setup result='" + result + "' on cid=" + cid);
         return result;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index ecd3380..979b8ba 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -822,11 +822,9 @@
                 mRetryMgr.resetRetryCount();
 
                 CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
-                int bsid = (loc != null) ? loc.getBaseStationId() : -1;
-
-                EventLog.List val = new EventLog.List(bsid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED,
+                        loc != null ? loc.getBaseStationId() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED, val);
             }
             trySetupData(Phone.REASON_CDMA_DATA_DETACHED);
         }
@@ -865,10 +863,9 @@
 
     private void writeEventLogCdmaDataDrop() {
         CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
-        int bsid = (loc != null) ? loc.getBaseStationId() : -1;
-        EventLog.List val = new EventLog.List(bsid,
+        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP,
+                loc != null ? loc.getBaseStationId() : -1,
                 TelephonyManager.getDefault().getNetworkType());
-        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP, val);
     }
 
     protected void onDataStateChanged(AsyncResult ar) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 8698b38..9289ad4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -537,11 +537,9 @@
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             DataConnectionTracker dcTracker = phone.mDataConnection;
             if (! dcTracker.isDataConnectionAsDesired()) {
-
-                EventLog.List val = new EventLog.List(
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF,
                         dcTracker.getStateInString(),
-                        (dcTracker.getAnyDataEnabled() ? 1 : 0) );
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val);
+                        dcTracker.getAnyDataEnabled() ? 1 : 0);
             }
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 91c089e..f4b9931 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -868,13 +868,10 @@
                     causeCode == CallFailCause.QOS_NOT_AVAIL ||
                     causeCode == CallFailCause.BEARER_NOT_AVAIL ||
                     causeCode == CallFailCause.ERROR_UNSPECIFIED) {
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-
-                    EventLog.List val = new EventLog.List(causeCode, cid,
-                        TelephonyManager.getDefault().getNetworkType());
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val);
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP,
+                            causeCode, loc != null ? loc.getCid() : -1,
+                            TelephonyManager.getDefault().getNetworkType());
                 }
 
                 for (int i = 0, s =  droppedDuringPoll.size()
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 5c97925..13407a3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -710,12 +710,10 @@
                 Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
 
                 // Add an event log when the network drops PDP
-                int cid = -1;
                 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                if (loc != null) cid = loc.getCid();
-                EventLog.List val = new EventLog.List(cid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP,
+                        loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
 
                 cleanUpConnection(true, null);
                 return;
@@ -733,12 +731,10 @@
                                     + " Reconnecting");
 
                     // Log the network drop on the event log.
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-                    EventLog.List val = new EventLog.List(cid,
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP,
+                            loc != null ? loc.getCid() : -1,
                             TelephonyManager.getDefault().getNetworkType());
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
 
                     cleanUpConnection(true, null);
                 }
@@ -1148,14 +1144,10 @@
             if(DBG) log("PDP setup failed " + cause);
                     // Log this failure to the Event Logs.
             if (cause.isEventLoggable()) {
-                int cid = -1;
                 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                if (loc != null) cid = loc.getCid();
-
-                EventLog.List val = new EventLog.List(
-                        cause.ordinal(), cid,
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL,
+                        cause.ordinal(), loc != null ? loc.getCid() : -1,
                         TelephonyManager.getDefault().getNetworkType());
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
             }
 
             // No try for permanent failure
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index f82474c..3e5f53c5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -482,12 +482,9 @@
                     // Can't register data sevice while voice service is ok
                     // i.e. CREG is ok while CGREG is not
                     // possible a network or baseband side error
-                    int cid = -1;
                     GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
-                    if (loc != null) cid = loc.getCid();
-
-                    EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid);
-                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val);
+                    EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL,
+                            ss.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
                     mReportedGprsNoReg = true;
                 }
                 mStartedGprsRegCheck = false;
@@ -518,11 +515,8 @@
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             DataConnectionTracker dcTracker = phone.mDataConnection;
             if (! dcTracker.isDataConnectionAsDesired()) {
-
-                EventLog.List val = new EventLog.List(
-                        dcTracker.getStateInString(),
-                        (dcTracker.getAnyDataEnabled() ? 1 : 0) );
-                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val);
+                EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF,
+                        dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0);
             }
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
diff --git a/tests/appwidgets/AppWidgetHostTest/Android.mk b/tests/appwidgets/AppWidgetHostTest/Android.mk
index 1bb1e54..4d0c704 100644
--- a/tests/appwidgets/AppWidgetHostTest/Android.mk
+++ b/tests/appwidgets/AppWidgetHostTest/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.mk b/tests/appwidgets/AppWidgetProviderTest/Android.mk
index c87a0f2..6084fb9 100644
--- a/tests/appwidgets/AppWidgetProviderTest/Android.mk
+++ b/tests/appwidgets/AppWidgetProviderTest/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
index 8263083..8afe35f 100644
--- a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
+++ b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
@@ -59,31 +59,21 @@
      }
 
     public void testLogOfListWithOneInt() throws Exception {
-        final EventLog.List list = new EventLog.List(1234);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, new Object[] {1234});
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1, numBytes);
     }
 
     public void testLogOfListWithMultipleInts() throws Exception {
-       final EventLog.List list = new EventLog.List(1234, 2345, 3456);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, new Object[] {1234, 2345, 3456});
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
     }
 
-    public void testLogOfListWithEmbeddedList() throws Exception {
-        final EventLog.List list = new EventLog.List(
-                new EventLog.List(1234, 2345, 3456));
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
-        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 2 + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
-    }
-
     public void testEventLargerThanInitialBufferCapacity() throws Exception {
         final Integer[] array = new Integer[127];
         for (int i = 0; i < array.length; i++) {
             array[i] = i;
         }
-        final EventLog.List list = new EventLog.List((Object[]) array);
-        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, (Object[]) array);
         Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + (5 * array.length) + 1, numBytes);
     }
 
@@ -117,8 +107,7 @@
     // This test is obsolete. See http://b/issue?id=1262082
     public void disableTestReadCompoundEntry() throws Exception {
         long when = System.currentTimeMillis();
-        EventLog.writeEvent(2719,
-                new EventLog.List(1l, new EventLog.List("2", "three", "4"), 5));
+        EventLog.writeEvent(2719, 1l, "2", 3);
         Log.i(TAG, "Wrote compound event at T=" + when);
 
         ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
@@ -129,18 +118,11 @@
             long eventTime = event.getTimeNanos() / 1000000;
             Log.i(TAG, "  Found event T=" + eventTime);
             if (eventTime > when - 100 && eventTime < when + 1000) {
-                EventLog.List data = (EventLog.List) event.getData();
-                assertEquals(data.getNumItems(), 3);
-
-                EventLog.List nested = (EventLog.List) data.getItem(1);
-                assertEquals(nested.getNumItems(), 3);
-
-                assertEquals(data.getItem(0), 1l);
-                assertEquals(nested.getItem(0), "2");
-                assertEquals(nested.getItem(1), "three");
-                assertEquals(nested.getItem(2), "4");
-                assertEquals(data.getItem(2), 5);
-
+                Object[] data = (Object[]) event.getData();
+                assertEquals(data.length, 3);
+                assertEquals(data[0], 1l);
+                assertEquals(data[1], "2");
+                assertEquals(data[2], 3);
                 assertFalse(found);
                 found = true;
             }
diff --git a/tests/framework-tests/src/android/util/EventLogTest.java b/tests/framework-tests/src/android/util/EventLogTest.java
index 4a5d888..2a9e9cd 100644
--- a/tests/framework-tests/src/android/util/EventLogTest.java
+++ b/tests/framework-tests/src/android/util/EventLogTest.java
@@ -33,13 +33,13 @@
 
     public void testIllegalListTypesThrowException() throws Exception {
         try {
-            EventLog.writeEvent(TEST_TAG, new EventLog.List(new Object()));
+            EventLog.writeEvent(TEST_TAG, new Object[]{new Object()});
             fail("Can't create List with any old Object");
         } catch (IllegalArgumentException e) {
             // expected
         }
         try {
-            EventLog.writeEvent(TEST_TAG, new EventLog.List((byte) 1));
+            EventLog.writeEvent(TEST_TAG, new Object[]{(byte) 1});
             fail("Can't create List with any old byte");
         } catch (IllegalArgumentException e) {
             // expected