Merge "temporarily skip simple-cross-origin-progress-events.html for now"
diff --git a/api/current.xml b/api/current.xml
index eb21d97..615cd93 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -16482,6 +16482,50 @@
  visibility="public"
 >
 </field>
+<field name="TextAppearance_StatusBar_EventContent"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973927"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_EventContent_Title"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973928"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_Icon"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973926"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_Title"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973925"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TextAppearance_Theme"
  type="int"
  transient="false"
@@ -17824,50 +17868,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad41"
- type="int"
- transient="false"
- volatile="false"
- value="16973928"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad42"
- type="int"
- transient="false"
- volatile="false"
- value="16973927"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad43"
- type="int"
- transient="false"
- volatile="false"
- value="16973926"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad44"
- type="int"
- transient="false"
- volatile="false"
- value="16973925"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad5"
  type="int"
  transient="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 2e87394..f6f80d1 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -136,7 +136,7 @@
 /* TODO(oam): depending on use case (ecryptfs or dmcrypt)
  * change implementation
  */
-static int disk_free()
+static int64_t disk_free()
 {
     struct statfs sfs;
     if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
@@ -154,18 +154,18 @@
  * also require that apps constantly modify file metadata even
  * when just reading from the cache, which is pretty awful.
  */
-int free_cache(int free_size)
+int free_cache(int64_t free_size)
 {
     const char *name;
     int dfd, subfd;
     DIR *d;
     struct dirent *de;
-    int avail;
+    int64_t avail;
 
     avail = disk_free();
     if (avail < 0) return -1;
 
-    LOGI("free_cache(%d) avail %d\n", free_size, avail);
+    LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
     if (avail >= free_size) return 0;
 
     /* First try encrypted dir */
@@ -327,10 +327,10 @@
     return 0;
 }
 
-static int stat_size(struct stat *s)
+static int64_t stat_size(struct stat *s)
 {
-    int blksize = s->st_blksize;
-    int size = s->st_size;
+    int64_t blksize = s->st_blksize;
+    int64_t size = s->st_size;
 
     if (blksize) {
             /* round up to filesystem block size */
@@ -340,9 +340,9 @@
     return size;
 }
 
-static int calculate_dir_size(int dfd)
+static int64_t calculate_dir_size(int dfd)
 {
-    int size = 0;
+    int64_t size = 0;
     struct stat s;
     DIR *d;
     struct dirent *de;
@@ -378,7 +378,7 @@
 
 int get_size(const char *pkgname, const char *apkpath,
              const char *fwdlock_apkpath,
-             int *_codesize, int *_datasize, int *_cachesize, int encrypted_fs_flag)
+             int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int encrypted_fs_flag)
 {
     DIR *d;
     int dfd;
@@ -386,9 +386,9 @@
     struct stat s;
     char path[PKG_PATH_MAX];
 
-    int codesize = 0;
-    int datasize = 0;
-    int cachesize = 0;
+    int64_t codesize = 0;
+    int64_t datasize = 0;
+    int64_t cachesize = 0;
 
         /* count the source apk as code -- but only if it's not
          * on the /system partition and its not on the sdcard.
@@ -445,7 +445,7 @@
             }
             subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
             if (subfd >= 0) {
-                int size = calculate_dir_size(subfd);
+                int64_t size = calculate_dir_size(subfd);
                 if (!strcmp(name,"lib")) {
                     codesize += size;
                 } else if(!strcmp(name,"cache")) {
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 882c493..c991845 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -60,7 +60,7 @@
 
 static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
 {
-    return free_cache(atoi(arg[0])); /* free_size */
+    return free_cache((int64_t)atoll(arg[0])); /* free_size */
 }
 
 static int do_rm_cache(char **arg, char reply[REPLY_MAX])
@@ -75,15 +75,19 @@
 
 static int do_get_size(char **arg, char reply[REPLY_MAX])
 {
-    int codesize = 0;
-    int datasize = 0;
-    int cachesize = 0;
+    int64_t codesize = 0;
+    int64_t datasize = 0;
+    int64_t cachesize = 0;
     int res = 0;
 
         /* pkgdir, apkpath */
     res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize, atoi(arg[3]));
 
-    sprintf(reply,"%d %d %d", codesize, datasize, cachesize);
+    /*
+     * Each int64_t can take up 22 characters printed out. Make sure it
+     * doesn't go over REPLY_MAX in the future.
+     */
+    snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize);
     return res;
 }
 
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 8e4adb1..479e4b2 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -19,6 +19,8 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
 #include <sys/stat.h>
 #include <dirent.h>
 #include <unistd.h>
@@ -105,7 +107,7 @@
 int rm_dex(const char *path);
 int protect(char *pkgname, gid_t gid);
 int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
-             int *codesize, int *datasize, int *cachesize, int encrypted_fs_flag);
-int free_cache(int free_size);
+             int64_t *codesize, int64_t *datasize, int64_t *cachesize, int encrypted_fs_flag);
+int free_cache(int64_t free_size);
 int dexopt(const char *apk_path, uid_t uid, int is_public);
 int movefiles();
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 4dc88b3..d7a0412 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -3,8 +3,6 @@
 import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
 
-import dalvik.system.PathClassLoader;
-
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -168,17 +166,14 @@
             // If the application does not have (Java) code, then no ClassLoader
             // has been set up for it.  We will need to do our own search for
             // the native code.
-            path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname);
-            if (!(new File(path)).exists()) {
-                path = null;
+            File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
+                    System.mapLibraryName(libname));
+            if (libraryFile.exists()) {
+                path = libraryFile.getPath();
             }
         }
         
         if (path == null) {
-            path = ((PathClassLoader)getClassLoader()).findLibrary(libname);
-        }
-        
-        if (path == null) {
             throw new IllegalArgumentException("Unable to find native library: " + libname);
         }
         
diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
index 23b1703..213bd31 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.app.QueuedWork;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.ParcelFileDescriptor;
@@ -94,7 +95,11 @@
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) {
         Context context = mContext;
-        
+
+        // If a SharedPreference has an outstanding write in flight,
+        // wait for it to finish flushing to disk.
+        QueuedWork.waitToFinish();
+
         // make filenames for the prefGroups
         String[] prefGroups = mPrefGroups;
         final int N = prefGroups.length;
@@ -123,4 +128,3 @@
         }
     }
 }
-
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index aa0a57d..9541380 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -144,6 +144,22 @@
         }
     }
 
+    @Override public String toString() {
+        synchronized(this) {
+            StringBuilder buff = new StringBuilder();
+            buff.append(" nStatement=");
+            buff.append(nStatement);
+            buff.append(", db=");
+            buff.append(mDatabase.getPath());
+            buff.append(", db_connectionNum=");
+            buff.append(mDatabase.mConnectionNum);
+            buff.append(", sql=");
+            int len = mSqlStmt.length();
+            buff.append(mSqlStmt.substring(0, (len > 100) ? 100 : len));
+            return buff.toString();
+        }
+    }
+
     /**
      * Compiles SQL into a SQLite program.
      *
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0137ea6..6937da0 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1066,7 +1066,7 @@
             closePendingStatements();
             releaseCustomFunctions();
             // close this database instance - regardless of its reference count value
-            dbclose();
+            closeDatabase();
             if (mConnectionPool != null) {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     assert mConnectionPool != null;
@@ -1075,7 +1075,7 @@
                 mConnectionPool.close();
             }
         } finally {
-            unlock();
+            unlock();            
         }
     }
 
@@ -1100,6 +1100,47 @@
     }
 
     /**
+     * package level access for testing purposes
+     */
+    /* package */ void closeDatabase() throws SQLiteException {
+        try {
+            dbclose();
+        } catch (SQLiteUnfinalizedObjectsException e)  {
+            String msg = e.getMessage();
+            String[] tokens = msg.split(",", 2);
+            int stmtId = Integer.parseInt(tokens[0]);
+            // get extra info about this statement, if it is still to be released by closeClosable()
+            Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
+            boolean found = false;
+            while (iter.hasNext()) {
+                Map.Entry<SQLiteClosable, Object> entry = iter.next();
+                SQLiteClosable program = entry.getKey();
+                if (program != null && program instanceof SQLiteProgram) {
+                        SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
+                        if (compiledSql.nStatement == stmtId) {
+                            msg = compiledSql.toString();
+                            found = true;
+                        }
+                }
+            }
+            if (!found) {
+                // the statement is already released by closeClosable(). is it waiting to be
+                // finalized?
+                if (mClosedStatementIds.contains(stmtId)) {
+                    Log.w(TAG, "this shouldn't happen. finalizing the statement now: ");
+                    closePendingStatements();
+                    // try to close the database again
+                    closeDatabase();
+                }
+            } else {
+                // the statement is not yet closed. most probably programming error in the app.
+                Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg);
+                throw e;
+            }
+        }
+    }
+
+    /**
      * Native call to close the database.
      */
     private native void dbclose();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 9b7d823..5e08aed 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -52,7 +52,7 @@
     /**
      * the SQLiteCompiledSql object for the given sql statement.
      */
-    private SQLiteCompiledSql mCompiledSql;
+    /* package */ SQLiteCompiledSql mCompiledSql;
 
     /**
      * SQLiteCompiledSql statement id is populated with the corresponding object from the above
diff --git a/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
new file mode 100644
index 0000000..bcf95e2
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.database.sqlite;
+
+/**
+ * Thrown if the database can't be closed because of some un-closed
+ * Cursor or SQLiteStatement objects. Could happen when a thread is trying to close
+ * the database while another thread still hasn't closed a Cursor on that database.
+ * @hide
+ */
+public class SQLiteUnfinalizedObjectsException extends SQLiteException {
+    public SQLiteUnfinalizedObjectsException() {}
+
+    public SQLiteUnfinalizedObjectsException(String error) {
+        super(error);
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9fe6e01..a857e58 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -216,6 +216,11 @@
         public abstract Map<Integer, ? extends Sensor> getSensorStats();
 
         /**
+         * Returns a mapping containing active process data.
+         */
+        public abstract SparseArray<? extends Pid> getPidStats();
+        
+        /**
          * Returns a mapping containing process statistics.
          *
          * @return a Map from Strings to Uid.Proc objects.
@@ -286,6 +291,11 @@
             public abstract Timer getSensorTime();
         }
 
+        public class Pid {
+            public long mWakeSum;
+            public long mWakeStart;
+        }
+
         /**
          * The statistics associated with a particular process.
          */
@@ -521,6 +531,11 @@
     public abstract HistoryItem getHistory();
     
     /**
+     * Return the base time offset for the battery history.
+     */
+    public abstract long getHistoryBaseTime();
+    
+    /**
      * Returns the number of times the device has been started.
      */
     public abstract int getStartCount();
@@ -1673,6 +1688,7 @@
         HistoryItem rec = getHistory();
         if (rec != null) {
             pw.println("Battery History:");
+            long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
             int oldState = 0;
             int oldStatus = -1;
             int oldHealth = -1;
@@ -1681,7 +1697,7 @@
             int oldVolt = -1;
             while (rec != null) {
                 pw.print("  ");
-                pw.print(rec.time);
+                TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                 pw.print(" ");
                 if (rec.cmd == HistoryItem.CMD_START) {
                     pw.println(" START");
@@ -1784,6 +1800,35 @@
                 oldState = rec.states;
                 rec = rec.next;
             }
+            pw.println("");
+        }
+        
+        SparseArray<? extends Uid> uidStats = getUidStats();
+        final int NU = uidStats.size();
+        boolean didPid = false;
+        long nowRealtime = SystemClock.elapsedRealtime();
+        StringBuilder sb = new StringBuilder(64);
+        for (int i=0; i<NU; i++) {
+            Uid uid = uidStats.valueAt(i);
+            SparseArray<? extends Uid.Pid> pids = uid.getPidStats();
+            if (pids != null) {
+                for (int j=0; j<pids.size(); j++) {
+                    Uid.Pid pid = pids.valueAt(j);
+                    if (!didPid) {
+                        pw.println("Per-PID Stats:");
+                        didPid = true;
+                    }
+                    long time = pid.mWakeSum + (pid.mWakeStart != 0
+                            ? (nowRealtime - pid.mWakeStart) : 0);
+                    pw.print("  PID "); pw.print(pids.keyAt(j));
+                            pw.print(" wake time: ");
+                            TimeUtils.formatDuration(time, pw);
+                            pw.println("");
+                }
+            }
+        }
+        if (didPid) {
+            pw.println("");
         }
         
         pw.println("Statistics since last charge:");
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 3fe14f9..0408673 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -34,7 +34,7 @@
      * An optional controller for the cursor.
      * Use {@link #setCursorController(CursorController)} to set this field.
      */
-    protected CursorController mCursorController;
+    private CursorController mCursorController;
 
     private boolean isCap(Spannable buffer) {
         return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
@@ -302,7 +302,17 @@
     /**
      * Defines the cursor controller.
      *
-     * When set, this object can be used to handle events, that can be translated in cursor updates.
+     * When set, this object can be used to handle touch events, that can be translated into cursor
+     * updates.
+     *
+     * {@link MotionEvent#ACTION_MOVE} events will call back the 
+     * {@link CursorController#updatePosition(int, int)} controller's method, passing the current
+     * finger coordinates (offset by {@link CursorController#getOffsetX()} and
+     * {@link CursorController#getOffsetY()}) as parameters. 
+     *
+     * When the gesture is finished (on a {@link MotionEvent#ACTION_UP} or
+     * {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null.
+     *
      * @param cursorController A cursor controller implementation
      */
     public void setCursorController(CursorController cursorController) {
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index b01a71d..60ca384 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -132,20 +132,76 @@
         return ZoneInfoDB.getVersion();
     }
 
+    /** @hide Field length that can hold 999 days of time */
+    public static final int HUNDRED_DAY_FIELD_LEN = 19;
+    
     private static final int SECONDS_PER_MINUTE = 60;
     private static final int SECONDS_PER_HOUR = 60 * 60;
     private static final int SECONDS_PER_DAY = 24 * 60 * 60;
 
-    /** @hide Just for debugging; not internationalized. */
-    public static void formatDuration(long duration, StringBuilder builder) {
-        if (duration == 0) {
-            builder.append("0");
-            return;
+    private static final Object sFormatSync = new Object();
+    private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
+    
+    static private int accumField(int amt, int suffix, boolean always, int zeropad) {
+        if (amt > 99 || (always && zeropad >= 3)) {
+            return 3+suffix;
         }
+        if (amt > 9 || (always && zeropad >= 2)) {
+            return 2+suffix;
+        }
+        if (always || amt > 0) {
+            return 1+suffix;
+        }
+        return 0;
+    }
+    
+    static private int printField(char[] formatStr, int amt, char suffix, int pos,
+            boolean always, int zeropad) {
+        if (always || amt > 0) {
+            if ((always && zeropad >= 3) || amt > 99) {
+                int dig = amt/100;
+                formatStr[pos] = (char)(dig + '0');
+                pos++;
+                always = true;
+                amt -= (dig*100);
+            }
+            if ((always && zeropad >= 2) || amt > 9) {
+                int dig = amt/10;
+                formatStr[pos] = (char)(dig + '0');
+                pos++;
+                always = true;
+                amt -= (dig*10);
+            }
+            formatStr[pos] = (char)(amt + '0');
+            pos++;
+            formatStr[pos] = suffix;
+            pos++;
+        }
+        return pos;
+    }
+    
+    private static int formatDurationLocked(long duration, int fieldLen) {
+        if (sFormatStr.length < fieldLen) {
+            sFormatStr = new char[fieldLen];
+        }
+        
+        char[] formatStr = sFormatStr;
+        
+        if (duration == 0) {
+            int pos = 0;
+            fieldLen -= 1;
+            while (pos < fieldLen) {
+                formatStr[pos] = ' ';
+            }
+            formatStr[pos] = '0';
+            return pos+1;
+        }
+        
+        char prefix;
         if (duration > 0) {
-            builder.append("+");
+            prefix = '+';
         } else {
-            builder.append("-");
+            prefix = '-';
             duration = -duration;
         }
 
@@ -166,93 +222,62 @@
             seconds -= minutes * SECONDS_PER_MINUTE;
         }
 
-        boolean doall = false;
-        if (days > 0) {
-            builder.append(days);
-            builder.append('d');
-            doall = true;
+        int pos = 0;
+        
+        if (fieldLen != 0) {
+            int myLen = accumField(days, 1, false, 0);
+            myLen += accumField(hours, 1, myLen > 0, 2);
+            myLen += accumField(minutes, 1, myLen > 0, 2);
+            myLen += accumField(seconds, 1, myLen > 0, 2);
+            myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1;
+            while (myLen < fieldLen) {
+                formatStr[pos] = ' ';
+                pos++;
+                myLen++;
+            }
         }
-        if (doall || hours > 0) {
-            builder.append(hours);
-            builder.append('h');
-            doall = true;
+        
+        formatStr[pos] = prefix;
+        pos++;
+        
+        int start = pos;
+        boolean zeropad = fieldLen != 0;
+        pos = printField(formatStr, days, 'd', pos, false, 0);
+        pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
+        pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
+        pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
+        pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
+        formatStr[pos] = 's';
+        return pos + 1;
+    }
+    
+    /** @hide Just for debugging; not internationalized. */
+    public static void formatDuration(long duration, StringBuilder builder) {
+        synchronized (sFormatSync) {
+            int len = formatDurationLocked(duration, 0);
+            builder.append(sFormatStr, 0, len);
         }
-        if (doall || minutes > 0) {
-            builder.append(minutes);
-            builder.append('m');
-            doall = true;
+    }
+
+    /** @hide Just for debugging; not internationalized. */
+    public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
+        synchronized (sFormatSync) {
+            int len = formatDurationLocked(duration, fieldLen);
+            pw.print(new String(sFormatStr, 0, len));
         }
-        if (doall || seconds > 0) {
-            builder.append(seconds);
-            builder.append('s');
-            doall = true;
-        }
-        builder.append(millis);
-        builder.append("ms");
     }
 
     /** @hide Just for debugging; not internationalized. */
     public static void formatDuration(long duration, PrintWriter pw) {
-        if (duration == 0) {
-            pw.print("0");
-            return;
-        }
-        if (duration > 0) {
-            pw.print("+");
-        } else {
-            pw.print("-");
-            duration = -duration;
-        }
-
-        int millis = (int)(duration%1000);
-        int seconds = (int) Math.floor(duration / 1000);
-        int days = 0, hours = 0, minutes = 0;
-
-        if (seconds > SECONDS_PER_DAY) {
-            days = seconds / SECONDS_PER_DAY;
-            seconds -= days * SECONDS_PER_DAY;
-        }
-        if (seconds > SECONDS_PER_HOUR) {
-            hours = seconds / SECONDS_PER_HOUR;
-            seconds -= hours * SECONDS_PER_HOUR;
-        }
-        if (seconds > SECONDS_PER_MINUTE) {
-            minutes = seconds / SECONDS_PER_MINUTE;
-            seconds -= minutes * SECONDS_PER_MINUTE;
-        }
-
-        boolean doall = false;
-        if (days > 0) {
-            pw.print(days);
-            pw.print('d');
-            doall = true;
-        }
-        if (doall || hours > 0) {
-            pw.print(hours);
-            pw.print('h');
-            doall = true;
-        }
-        if (doall || minutes > 0) {
-            pw.print(minutes);
-            pw.print('m');
-            doall = true;
-        }
-        if (doall || seconds > 0) {
-            pw.print(seconds);
-            pw.print('s');
-            doall = true;
-        }
-        pw.print(millis);
-        pw.print("ms");
+        formatDuration(duration, pw, 0);
     }
-
-
+    
     /** @hide Just for debugging; not internationalized. */
     public static void formatDuration(long time, long now, PrintWriter pw) {
         if (time == 0) {
             pw.print("--");
             return;
         }
-        formatDuration(time-now, pw);
+        formatDuration(time-now, pw, 0);
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7355353..f8d79e5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7298,9 +7298,6 @@
             if (ViewDebug.TRACE_HIERARCHY) {
                 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
             }
-            if (Config.DEBUG && ViewDebug.profileDrawing) {
-                EventLog.writeEvent(60002, hashCode());
-            }
 
             int width = mRight - mLeft;
             int height = mBottom - mTop;
@@ -7738,7 +7735,8 @@
         saveCount = canvas.getSaveCount();
 
         int solidColor = getSolidColor();
-        if (solidColor == 0) {
+        // TODO: Temporarily disable fading edges with hardware acceleration
+        if (solidColor == 0 && !canvas.isHardwareAccelerated()) {
             final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
 
             if (drawTop) {
@@ -7946,6 +7944,7 @@
      * @param r Right position, relative to parent
      * @param b Bottom position, relative to parent
      */
+    @SuppressWarnings({"unchecked"})
     public final void layout(int l, int t, int r, int b) {
         int oldL = mLeft;
         int oldT = mTop;
@@ -10129,11 +10128,6 @@
         final RectF mTmpTransformRect = new RectF();
 
         /**
-         * Temporary for use in computing invalidation areas with transformed views
-         */
-        final float[] mTmpTransformBounds = new float[8];
-
-        /**
          * Temporary list for use in collecting focusable descendents of a view.
          */
         final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 22cc3a8..b1d5272 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -119,24 +119,21 @@
      *
      * @hide
      */
-    @Debug.DebugProperty
-    public static boolean profileDrawing = false;
+    public static final boolean DEBUG_PROFILE_DRAWING = false;
 
     /**
      * Profiles layout times in the events log.
      *
      * @hide
      */
-    @Debug.DebugProperty
-    public static boolean profileLayout = false;
+    public static final boolean DEBUG_PROFILE_LAYOUT = false;
 
     /**
      * Profiles real fps (times between draws) and displays the result.
      *
      * @hide
      */
-    @Debug.DebugProperty
-    public static boolean showFps = false;
+    public static final boolean DEBUG_SHOW_FPS = false;
 
     /**
      * <p>Enables or disables views consistency check. Even when this property is enabled,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dee6e73..363ccd6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,8 +32,6 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.util.Config;
-import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.accessibility.AccessibilityEvent;
@@ -2020,9 +2018,6 @@
                 cachePaint.setAlpha(255);
                 mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
             }
-            if (Config.DEBUG && ViewDebug.profileDrawing) {
-                EventLog.writeEvent(60003, hashCode());
-            }
             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
         }
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 5d4ac37..e5fc859 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -946,8 +946,8 @@
                     mSurfaceHolder.mSurfaceLock.unlock();
                 }
             }
-            
-            if (hwIntialized) {
+
+            if (hwIntialized || (windowShouldResize && mHwRenderer != null)) {
                 mHwRenderer.setup(mWidth, mHeight);
             }
 
@@ -1008,7 +1008,7 @@
                 TAG, "Laying out " + host + " to (" +
                 host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
             long startTime = 0L;
-            if (ViewDebug.profileLayout) {
+            if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
                 startTime = SystemClock.elapsedRealtime();
             }
             host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
@@ -1021,7 +1021,7 @@
                 }
             }
 
-            if (ViewDebug.profileLayout) {
+            if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
                 EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
             }
 
@@ -1321,7 +1321,7 @@
                         //canvas.drawARGB(255, 255, 0, 0);
                     }
 
-                    if (ViewDebug.profileDrawing) {
+                    if (ViewDebug.DEBUG_PROFILE_DRAWING) {
                         startTime = SystemClock.elapsedRealtime();
                     }
 
@@ -1364,7 +1364,7 @@
                         mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
                     }
 
-                    if (SHOW_FPS || ViewDebug.showFps) {
+                    if (SHOW_FPS || ViewDebug.DEBUG_SHOW_FPS) {
                         int now = (int)SystemClock.elapsedRealtime();
                         if (sDrawTime != 0) {
                             nativeShowFPS(canvas, now - sDrawTime);
@@ -1372,7 +1372,7 @@
                         sDrawTime = now;
                     }
 
-                    if (ViewDebug.profileDrawing) {
+                    if (ViewDebug.DEBUG_PROFILE_DRAWING) {
                         EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
                     }
                 }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0ed5fc5..d81d7f2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -211,6 +211,7 @@
     private boolean         mNavDump = false;
     private boolean         mSupportZoom = true;
     private boolean         mBuiltInZoomControls = false;
+    private boolean         mDisplayZoomControls = true;
     private boolean         mAllowFileAccess = true;
     private boolean         mLoadWithOverviewMode = false;
     private boolean         mEnableSmoothTransition = false;
@@ -508,6 +509,26 @@
     }
 
     /**
+     * Sets whether the on screen zoom buttons are used.
+     * A combination of built in zoom controls enabled
+     * and on screen zoom controls disabled allows for pinch to zoom
+     * to work without the on screen controls
+     * @hide
+     */
+    public void setDisplayZoomControls(boolean enabled) {
+        mDisplayZoomControls = enabled;
+        mWebView.updateMultiTouchSupport(mContext);
+    }
+
+    /**
+     * Returns true if the on screen zoom buttons are being used.
+     * @hide
+     */
+    public boolean getDisplayZoomControls() {
+        return mDisplayZoomControls;
+    }
+
+    /**
      * Enable or disable file access within WebView. File access is enabled by
      * default.
      */
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 33ebcf5..1323217 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -856,7 +856,8 @@
     private ZoomControlBase getCurrentZoomControl() {
         if (mWebView.getSettings() != null && mWebView.getSettings().supportZoom()) {
             if (mWebView.getSettings().getBuiltInZoomControls()) {
-                if (mEmbeddedZoomControl == null) {
+                if ((mEmbeddedZoomControl == null)
+                        && mWebView.getSettings().getDisplayZoomControls()) {
                     mEmbeddedZoomControl = new ZoomControlEmbedded(this, mWebView);
                 }
                 return mEmbeddedZoomControl;
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 0636d72..830e899 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -31,6 +31,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
@@ -128,6 +129,13 @@
     boolean mShouldLoop = true;
 
     /**
+     * The width and height of some child, used as a size reference in-case our
+     * dimensions are unspecified by the parent.
+     */
+    int mReferenceChildWidth = -1;
+    int mReferenceChildHeight = -1;
+
+    /**
      * TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit.
      */
     Animation mInAnimation;
@@ -414,7 +422,7 @@
                         FrameLayout fl = new FrameLayout(mContext);
                         fl.addView(newView);
                         mActiveViews[index] = fl;
-                        addViewInLayout(fl, -1, createOrReuseLayoutParams(fl));
+                        addChild(fl);
                         applyTransformForChildAtIndex(fl, newRelativeIndex);
                         animateViewForTransition(-1, newRelativeIndex, fl);
                     }
@@ -451,6 +459,64 @@
         }
     }
 
+    private void addChild(View child) {
+        addViewInLayout(child, -1, createOrReuseLayoutParams(child));
+
+        // This code is used to obtain a reference width and height of a child in case we need
+        // to decide our own size. TODO: Do we want to update the size of the child that we're
+        // using for reference size? If so, when?
+        if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) {
+            int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            child.measure(measureSpec, measureSpec);
+            mReferenceChildWidth = child.getMeasuredWidth();
+            mReferenceChildHeight = child.getMeasuredHeight();
+        }
+    }
+
+    private void measureChildren() {
+        final int count = getChildCount();
+        final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+        final int childHeight = mMeasuredHeight - mPaddingTop - mPaddingBottom;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+        boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+        // We need to deal with the case where our parent hasn't told us how
+        // big we should be. In this case we try to use the desired size of the first
+        // child added.
+        if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+            heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop +
+                    mPaddingBottom : 0;
+        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+            heightSpecSize = haveChildRefSize ? Math.min(mReferenceChildHeight + mPaddingTop +
+                    mPaddingBottom, heightSpecSize) : 0;
+        }
+
+        if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+            widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+                    mPaddingRight : 0;
+        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+            widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+                    mPaddingRight, widthSpecSize) : 0;
+        }
+
+        setMeasuredDimension(widthSpecSize, heightSpecSize);
+        measureChildren();
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         boolean dataChanged = mDataChanged;
@@ -472,8 +538,7 @@
             int childRight = mPaddingLeft + child.getMeasuredWidth();
             int childBottom = mPaddingTop + child.getMeasuredHeight();
 
-            child.layout(mPaddingLeft, mPaddingTop,
-                    childRight, childBottom);
+            child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom);
         }
         mDataChanged = false;
     }
@@ -538,31 +603,6 @@
         setDisplayedChild(mWhichChild);
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int count = getChildCount();
-
-        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            lp.width = widthSpecSize - mPaddingLeft - mPaddingRight;
-            lp.height = heightSpecSize - mPaddingTop - mPaddingBottom;
-
-            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
-                    MeasureSpec.EXACTLY);
-            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
-                    MeasureSpec.EXACTLY);
-
-            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-        }
-        setMeasuredDimension(widthSpecSize, heightSpecSize);
-    }
-
     /**
      * Shows only the specified child. The other displays Views exit the screen
      * with the {@link #getOutAnimation() out animation} and the specified child
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 50fbb6b..5598c65 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -247,6 +247,7 @@
                         trigger = true;
                         createUri = Uri.fromParts("tel", (String)cookie, null);
 
+                        //$FALL-THROUGH$
                     case TOKEN_PHONE_LOOKUP: {
                         if (cursor != null && cursor.moveToFirst()) {
                             long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
@@ -260,12 +261,14 @@
                         trigger = true;
                         createUri = Uri.fromParts("mailto", (String)cookie, null);
 
+                        //$FALL-THROUGH$
                     case TOKEN_EMAIL_LOOKUP: {
                         if (cursor != null && cursor.moveToFirst()) {
                             long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
                             String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
                             lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                         }
+                        break;
                     }
 
                     case TOKEN_CONTACT_LOOKUP_AND_TRIGGER: {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 9816b39..9025b83 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -16,11 +16,11 @@
 
 package android.widget;
 
-import java.util.WeakHashMap;
-
 import android.animation.PropertyAnimator;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -28,6 +28,7 @@
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.TableMaskFilter;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -35,6 +36,8 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
 import android.view.animation.LinearInterpolator;
 import android.widget.RemoteViews.RemoteView;
 
@@ -53,6 +56,19 @@
     private final int MINIMUM_ANIMATION_DURATION = 50;
 
     /**
+     * Parameters effecting the perspective visuals
+     */
+    private static float PERSPECTIVE_SHIFT_FACTOR = 0.12f;
+    private static float PERSPECTIVE_SCALE_FACTOR = 0.35f;
+
+    /**
+     * Represent the two possible stack modes, one where items slide up, and the other
+     * where items slide down. The perspective is also inverted between these two modes.
+     */
+    private static final int ITEMS_SLIDE_UP = 0;
+    private static final int ITEMS_SLIDE_DOWN = 1;
+
+    /**
      * These specify the different gesture states
      */
     private static final int GESTURE_NONE = 0;
@@ -66,8 +82,6 @@
     private static final float SWIPE_THRESHOLD_RATIO = 0.35f;
     private static final float SLIDE_UP_RATIO = 0.7f;
 
-    private final WeakHashMap<View, Float> mRotations = new WeakHashMap<View, Float>();
-
     /**
      * Sentinel value for no current active pointer.
      * Used by {@link #mActivePointerId}.
@@ -75,6 +89,12 @@
     private static final int INVALID_POINTER = -1;
 
     /**
+     * Number of active views in the stack. One fewer view is actually visible, as one is hidden.
+     */
+    private static final int NUM_ACTIVE_VIEWS = 5;
+
+
+    /**
      * These variables are all related to the current state of touch interaction
      * with the stack
      */
@@ -95,6 +115,7 @@
     private boolean mFirstLayoutHappened = false;
     private ViewGroup mAncestorContainingAllChildren = null;
     private int mAncestorHeight = 0;
+    private int mStackMode;
 
     public StackView(Context context) {
         super(context);
@@ -107,7 +128,7 @@
     }
 
     private void initStackView() {
-        configureViewAnimator(4, 2, false);
+        configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2, false);
         setStaticTransformationsEnabled(true);
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledTouchSlop();
@@ -125,6 +146,11 @@
         setClipChildren(false);
         setClipToPadding(false);
 
+        // This sets the form of the StackView, which is currently to have the perspective-shifted
+        // views above the active view, and have items slide down when sliding out. The opposite is
+        // available by using ITEMS_SLIDE_UP.
+        mStackMode = ITEMS_SLIDE_DOWN;
+
         // This is a flag to indicate the the stack is loading for the first time
         mWhichChild = -1;
     }
@@ -140,7 +166,7 @@
             }
             view.setVisibility(VISIBLE);
 
-            PropertyAnimator fadeIn = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
+            PropertyAnimator<Float> fadeIn = new PropertyAnimator<Float>(DEFAULT_ANIMATION_DURATION,
                     view, "alpha", view.getAlpha(), 1.0f);
             fadeIn.start();
         } else if (fromIndex == mNumActiveViews - 1 && toIndex == mNumActiveViews - 2) {
@@ -148,49 +174,32 @@
             view.setVisibility(VISIBLE);
 
             LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            int largestDuration =
-                Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
-
-            int duration = largestDuration;
-            if (mYVelocity != 0) {
-                duration = 1000*(0 - lp.verticalOffset)/Math.abs(mYVelocity);
-            }
-
-            duration = Math.min(duration, largestDuration);
-            duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+            int duration = Math.round(mStackSlider.getDurationForNeutralPosition(mYVelocity));
 
             StackSlider animationSlider = new StackSlider(mStackSlider);
-            PropertyAnimator slideInY = new PropertyAnimator(duration, animationSlider,
-                    "YProgress", mStackSlider.getYProgress(), 0);
-            slideInY.setInterpolator(new LinearInterpolator());
-            slideInY.start();
-            PropertyAnimator slideInX = new PropertyAnimator(duration, animationSlider,
-                    "XProgress", mStackSlider.getXProgress(), 0);
-            slideInX.setInterpolator(new LinearInterpolator());
-            slideInX.start();
+            PropertyValuesHolder<Float> slideInY =
+                    new PropertyValuesHolder<Float>("YProgress", 0.0f);
+            PropertyValuesHolder<Float> slideInX =
+                    new PropertyValuesHolder<Float>("XProgress", 0.0f);
+            PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+                    slideInX, slideInY);
+            pa.setInterpolator(new LinearInterpolator());
+            pa.start();
         } else if (fromIndex == mNumActiveViews - 2 && toIndex == mNumActiveViews - 1) {
             // Slide item out
             LayoutParams lp = (LayoutParams) view.getLayoutParams();
 
-            int largestDuration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
-                    DEFAULT_ANIMATION_DURATION);
-            int duration = largestDuration;
-            if (mYVelocity != 0) {
-                duration = 1000*(lp.verticalOffset + mViewHeight)/Math.abs(mYVelocity);
-            }
-
-            duration = Math.min(duration, largestDuration);
-            duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+            int duration = Math.round(mStackSlider.getDurationForOffscreenPosition(mYVelocity));
 
             StackSlider animationSlider = new StackSlider(mStackSlider);
-            PropertyAnimator slideOutY = new PropertyAnimator(duration, animationSlider,
-                    "YProgress", mStackSlider.getYProgress(), 1);
-            slideOutY.setInterpolator(new LinearInterpolator());
-            slideOutY.start();
-            PropertyAnimator slideOutX = new PropertyAnimator(duration, animationSlider,
-                    "XProgress", mStackSlider.getXProgress(), 0);
-            slideOutX.setInterpolator(new LinearInterpolator());
-            slideOutX.start();
+            PropertyValuesHolder<Float> slideOutY =
+                    new PropertyValuesHolder<Float>("YProgress", 1.0f);
+            PropertyValuesHolder<Float> slideOutX =
+                    new PropertyValuesHolder<Float>("XProgress", 0.0f);
+            PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+                   slideOutX, slideOutY);
+            pa.setInterpolator(new LinearInterpolator());
+            pa.start();
         } else if (fromIndex == -1 && toIndex == mNumActiveViews - 1) {
             // Make sure this view that is "waiting in the wings" is invisible
             view.setAlpha(0.0f);
@@ -199,28 +208,41 @@
             lp.setVerticalOffset(-mViewHeight);
         } else if (toIndex == -1) {
             // Fade item out
-            PropertyAnimator fadeOut = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
-                    view, "alpha", view.getAlpha(), 0);
+            PropertyAnimator<Float> fadeOut = new PropertyAnimator<Float>
+                    (DEFAULT_ANIMATION_DURATION, view, "alpha", view.getAlpha(), 0.0f);
             fadeOut.start();
         }
+
+        // Implement the faked perspective
+        if (toIndex != -1) {
+            float maxPerpectiveShift = mViewHeight * PERSPECTIVE_SHIFT_FACTOR;
+            int index = toIndex;
+
+            if (toIndex == mNumActiveViews -1) index--;
+
+            float r = (index * 1.0f) / (mNumActiveViews - 2);
+
+            float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
+            PropertyValuesHolder<Float> scaleX = new PropertyValuesHolder<Float>("scaleX", scale);
+            PropertyValuesHolder<Float> scaleY = new PropertyValuesHolder<Float>("scaleY", scale);
+
+            r = (float) Math.pow(r, 2);
+
+            int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+            float transY = -stackDirection * r * maxPerpectiveShift +
+                    stackDirection * (1 - scale) * (mViewHeight / 2.0f);
+
+            PropertyValuesHolder<Float> translationY =
+                    new PropertyValuesHolder<Float>("translationY", transY);
+            PropertyAnimator pa = new PropertyAnimator(100, view, scaleX, scaleY, translationY);
+            pa.start();
+        }
     }
 
     /**
      * Apply any necessary tranforms for the child that is being added.
      */
     void applyTransformForChildAtIndex(View child, int relativeIndex) {
-        if (!mRotations.containsKey(child)) {
-            float rotation = (float) (Math.random()*26 - 13);
-            mRotations.put(child, rotation);
-            child.setRotation(rotation);
-        }
-
-        // Child has been removed
-        if (relativeIndex == -1) {
-            if (mRotations.containsKey(child)) {
-                mRotations.remove(child);
-            }
-        }
     }
 
     @Override
@@ -248,8 +270,8 @@
 
     private void onLayout() {
         if (!mFirstLayoutHappened) {
-            mViewHeight = Math.round(SLIDE_UP_RATIO*getMeasuredHeight());
-            mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO*mViewHeight);
+            mViewHeight = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
+            mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * mViewHeight);
             mFirstLayoutHappened = true;
         }
     }
@@ -299,8 +321,14 @@
             cancelLongPress();
             requestDisallowInterceptTouchEvent(true);
 
-            int activeIndex = swipeGestureType == GESTURE_SLIDE_DOWN ? mNumActiveViews - 1
-                    : mNumActiveViews - 2;
+            int activeIndex;
+            if (mStackMode == ITEMS_SLIDE_UP) {
+                activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+                        mNumActiveViews - 1 : mNumActiveViews - 2;
+            } else {
+                activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+                        mNumActiveViews - 2 : mNumActiveViews - 1;
+            }
 
             if (mAdapter == null) return;
 
@@ -317,6 +345,8 @@
             if (v == null) return;
 
             mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
+            mHighlight.setRotation(v.getRotation());
+            mHighlight.setTranslationY(v.getTranslationY());
             mHighlight.bringToFront();
             v.bringToFront();
             mStackSlider.setView(v);
@@ -352,14 +382,16 @@
             case MotionEvent.ACTION_MOVE: {
                 beginGestureIfNeeded(deltaY);
 
-                float rx = deltaX/(mViewHeight*1.0f);
+                float rx = deltaX / (mViewHeight * 1.0f);
                 if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
-                    float r = (deltaY-mTouchSlop*1.0f)/mViewHeight*1.0f;
+                    float r = (deltaY - mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+                    if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
                     mStackSlider.setYProgress(1 - r);
                     mStackSlider.setXProgress(rx);
                     return true;
                 } else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
-                    float r = -(deltaY + mTouchSlop*1.0f)/mViewHeight*1.0f;
+                    float r = -(deltaY + mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+                    if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
                     mStackSlider.setYProgress(r);
                     mStackSlider.setXProgress(rx);
                     return true;
@@ -447,41 +479,59 @@
         if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN
                 && mStackSlider.mMode == StackSlider.NORMAL_MODE) {
             // Swipe threshold exceeded, swipe down
-            showNext();
+            if (mStackMode == ITEMS_SLIDE_UP) {
+                showNext();
+            } else {
+                showPrevious();
+            }
             mHighlight.bringToFront();
         } else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP
                 && mStackSlider.mMode == StackSlider.NORMAL_MODE) {
             // Swipe threshold exceeded, swipe up
-            showPrevious();
+            if (mStackMode == ITEMS_SLIDE_UP) {
+                showPrevious();
+            } else {
+                showNext();
+            }
+
             mHighlight.bringToFront();
-        } else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
+        } else if (mSwipeGestureType == GESTURE_SLIDE_UP ) {
             // Didn't swipe up far enough, snap back down
-            int duration =
-                Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
+            int duration;
+            float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 1 : 0;
+            if (mStackMode == ITEMS_SLIDE_UP || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+                duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+            } else {
+                duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+            }
 
             StackSlider animationSlider = new StackSlider(mStackSlider);
-            PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
-                    "YProgress", mStackSlider.getYProgress(), 0);
-            snapBackY.setInterpolator(new LinearInterpolator());
-            snapBackY.start();
-            PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
-                    "XProgress", mStackSlider.getXProgress(), 0);
-            snapBackX.setInterpolator(new LinearInterpolator());
-            snapBackX.start();
+            PropertyValuesHolder<Float> snapBackY =
+                    new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+            PropertyValuesHolder<Float> snapBackX =
+                    new PropertyValuesHolder<Float>("XProgress", 0.0f);
+            PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+                    snapBackX, snapBackY);
+            pa.setInterpolator(new LinearInterpolator());
+            pa.start();
         } else if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
             // Didn't swipe down far enough, snap back up
-            int duration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
-                    DEFAULT_ANIMATION_DURATION);
+            float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 0 : 1;
+            int duration;
+            if (mStackMode == ITEMS_SLIDE_DOWN || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+                duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+            } else {
+                duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+            }
 
             StackSlider animationSlider = new StackSlider(mStackSlider);
-            PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
-                    "YProgress", mStackSlider.getYProgress(), 1);
-            snapBackY.setInterpolator(new LinearInterpolator());
-            snapBackY.start();
-            PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
-                    "XProgress", mStackSlider.getXProgress(), 0);
-            snapBackX.setInterpolator(new LinearInterpolator());
-            snapBackX.start();
+            PropertyValuesHolder<Float> snapBackY =
+                    new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+            PropertyValuesHolder<Float> snapBackX =
+                    new PropertyValuesHolder<Float>("XProgress", 0.0f);
+            PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+                    snapBackX, snapBackY);
+            pa.start();
         }
 
         mActivePointerId = INVALID_POINTER;
@@ -510,22 +560,22 @@
         }
 
         private float cubic(float r) {
-            return (float) (Math.pow(2*r-1, 3) + 1)/2.0f;
+            return (float) (Math.pow(2 * r - 1, 3) + 1) / 2.0f;
         }
 
         private float highlightAlphaInterpolator(float r) {
             float pivot = 0.4f;
             if (r < pivot) {
-                return 0.85f*cubic(r/pivot);
+                return 0.85f * cubic(r / pivot);
             } else {
-                return 0.85f*cubic(1 - (r-pivot)/(1-pivot));
+                return 0.85f * cubic(1 - (r - pivot) / (1 - pivot));
             }
         }
 
         private float viewAlphaInterpolator(float r) {
             float pivot = 0.3f;
             if (r > pivot) {
-                return (r - pivot)/(1 - pivot);
+                return (r - pivot) / (1 - pivot);
             } else {
                 return 0;
             }
@@ -536,7 +586,7 @@
             if (r < pivot) {
                 return 0;
             } else {
-                return (r-pivot)/(1-pivot);
+                return (r - pivot) / (1 - pivot);
             }
         }
 
@@ -553,13 +603,15 @@
             final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
             final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
 
+            int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+
             switch (mMode) {
                 case NORMAL_MODE:
-                    viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
-                    highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+                    viewLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
+                    highlightLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
                     mHighlight.setAlpha(highlightAlphaInterpolator(r));
 
-                    float alpha = viewAlphaInterpolator(1-r);
+                    float alpha = viewAlphaInterpolator(1 - r);
 
                     // We make sure that views which can't be seen (have 0 alpha) are also invisible
                     // so that they don't interfere with click events.
@@ -571,19 +623,19 @@
                     }
 
                     mView.setAlpha(alpha);
-                    mView.setRotationX(90.0f*rotationInterpolator(r));
-                    mHighlight.setRotationX(90.0f*rotationInterpolator(r));
+                    mView.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
+                    mHighlight.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
                     break;
                 case BEGINNING_OF_STACK_MODE:
-                    r = r*0.2f;
-                    viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
-                    highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+                    r = r * 0.2f;
+                    viewLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
+                    highlightLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
                     mHighlight.setAlpha(highlightAlphaInterpolator(r));
                     break;
                 case END_OF_STACK_MODE:
-                    r = (1-r)*0.2f;
-                    viewLp.setVerticalOffset(Math.round(r*mViewHeight));
-                    highlightLp.setVerticalOffset(Math.round(r*mViewHeight));
+                    r = (1-r) * 0.2f;
+                    viewLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
+                    highlightLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
                     mHighlight.setAlpha(highlightAlphaInterpolator(r));
                     break;
             }
@@ -600,8 +652,8 @@
             final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
 
             r *= 0.2f;
-            viewLp.setHorizontalOffset(Math.round(r*mViewHeight));
-            highlightLp.setHorizontalOffset(Math.round(r*mViewHeight));
+            viewLp.setHorizontalOffset(Math.round(r * mViewHeight));
+            highlightLp.setHorizontalOffset(Math.round(r * mViewHeight));
         }
 
         void setMode(int mode) {
@@ -609,31 +661,51 @@
         }
 
         float getDurationForNeutralPosition() {
-            return getDuration(false);
+            return getDuration(false, 0);
         }
 
         float getDurationForOffscreenPosition() {
-            return getDuration(mMode == END_OF_STACK_MODE ? false : true);
+            return getDuration(true, 0);
         }
 
-        private float getDuration(boolean invert) {
+        float getDurationForNeutralPosition(float velocity) {
+            return getDuration(false, velocity);
+        }
+
+        float getDurationForOffscreenPosition(float velocity) {
+            return getDuration(true, velocity);
+        }
+
+        private float getDuration(boolean invert, float velocity) {
             if (mView != null) {
                 final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
 
-                float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset,2) +
-                        Math.pow(viewLp.verticalOffset,2));
+                float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset, 2) +
+                        Math.pow(viewLp.verticalOffset, 2));
                 float maxd = (float) Math.sqrt(Math.pow(mViewHeight, 2) +
-                        Math.pow(0.4f*mViewHeight, 2));
-                return invert ? (1-d/maxd) : d/maxd;
+                        Math.pow(0.4f * mViewHeight, 2));
+
+                if (velocity == 0) {
+                    return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION;
+                } else {
+                    float duration = invert ? d / Math.abs(velocity) :
+                            (maxd - d) / Math.abs(velocity);
+                    if (duration < MINIMUM_ANIMATION_DURATION ||
+                            duration > DEFAULT_ANIMATION_DURATION) {
+                        return getDuration(invert, 0);
+                    } else {
+                        return duration;
+                    }
+                }
             }
             return 0;
         }
 
-        float getYProgress() {
+        public float getYProgress() {
             return mYProgress;
         }
 
-        float getXProgress() {
+        public float getXProgress() {
             return mXProgress;
         }
     }
@@ -654,6 +726,8 @@
             LayoutParams lp = (LayoutParams) currentLp;
             lp.setHorizontalOffset(0);
             lp.setVerticalOffset(0);
+            lp.width = 0;
+            lp.width = 0;
             return lp;
         }
         return new LayoutParams(v);
@@ -684,15 +758,59 @@
             child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset,
                     childRight + lp.horizontalOffset, childBottom + lp.verticalOffset);
 
-            //TODO: temp until fix in View
-            child.setPivotX(child.getMeasuredWidth()/2);
-            child.setPivotY(child.getMeasuredHeight()/2);
         }
 
         mDataChanged = false;
         onLayout();
     }
 
+    private void measureChildren() {
+        final int count = getChildCount();
+        final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+        final int childHeight = Math.round(mMeasuredHeight*(1-PERSPECTIVE_SHIFT_FACTOR))
+                - mPaddingTop - mPaddingBottom;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+        boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+        // We need to deal with the case where our parent hasn't told us how
+        // big we should be. In this case we should
+        float factor = 1/(1 - PERSPECTIVE_SHIFT_FACTOR);
+        if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+            heightSpecSize = haveChildRefSize ?
+                    Math.round(mReferenceChildHeight * (1 + factor)) +
+                    mPaddingTop + mPaddingBottom : 0;
+        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+            heightSpecSize = haveChildRefSize ? Math.min(
+                    Math.round(mReferenceChildHeight * (1 + factor)) + mPaddingTop +
+                    mPaddingBottom, heightSpecSize) : 0;
+        }
+
+        if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+            widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+                    mPaddingRight : 0;
+        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+            widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+                    mPaddingRight, widthSpecSize) : 0;
+        }
+
+        setMeasuredDimension(widthSpecSize, heightSpecSize);
+        measureChildren();
+    }
+
     class LayoutParams extends ViewGroup.LayoutParams {
         int horizontalOffset;
         int verticalOffset;
@@ -700,6 +818,8 @@
 
         LayoutParams(View view) {
             super(0, 0);
+            width = 0;
+            height = 0;
             horizontalOffset = 0;
             verticalOffset = 0;
             mView = view;
@@ -709,6 +829,8 @@
             super(c, attrs);
             horizontalOffset = 0;
             verticalOffset = 0;
+            width = 0;
+            height = 0;
         }
 
         private Rect parentRect = new Rect();
@@ -731,6 +853,10 @@
                 gp = (View) p.getParent();
                 parentRect.set(p.getLeft() - gp.getScrollX(), p.getTop() - gp.getScrollY(),
                         p.getRight() - gp.getScrollX(), p.getBottom() - gp.getScrollY());
+
+                // TODO: we need to stop early here if we've hit the edge of the screen
+                // so as to prevent us from walking too high in the hierarchy. A lot of this
+                // code might become a lot more straightforward.
             }
 
             if (depth > mAncestorHeight) {
@@ -799,7 +925,7 @@
     private static class HolographicHelper {
         private final Paint mHolographicPaint = new Paint();
         private final Paint mErasePaint = new Paint();
-        private final float STROKE_WIDTH = 3.0f;
+        private final Paint mBlurPaint = new Paint();
 
         HolographicHelper() {
             initializePaints();
@@ -808,8 +934,10 @@
         void initializePaints() {
             mHolographicPaint.setColor(0xff6699ff);
             mHolographicPaint.setFilterBitmap(true);
+            mHolographicPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
             mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
             mErasePaint.setFilterBitmap(true);
+            mBlurPaint.setMaskFilter(new BlurMaskFilter(2, BlurMaskFilter.Blur.NORMAL));
         }
 
         Bitmap createOutline(View v) {
@@ -822,31 +950,31 @@
             Canvas canvas = new Canvas(bitmap);
 
             float rotationX = v.getRotationX();
+            float rotation = v.getRotation();
+            float translationY = v.getTranslationY();
             v.setRotationX(0);
+            v.setRotation(0);
+            v.setTranslationY(0);
             canvas.concat(v.getMatrix());
             v.draw(canvas);
-
             v.setRotationX(rotationX);
+            v.setRotation(rotation);
+            v.setTranslationY(translationY);
+            canvas.setMatrix(id);
 
             drawOutline(canvas, bitmap);
             return bitmap;
         }
 
         final Matrix id = new Matrix();
-        final Matrix scaleMatrix = new Matrix();
         void drawOutline(Canvas dest, Bitmap src) {
-            Bitmap mask = src.extractAlpha();
-
+            int[] xy = new int[2];
+            Bitmap mask = src.extractAlpha(mBlurPaint, xy);
+            Canvas maskCanvas = new Canvas(mask);
+            maskCanvas.drawBitmap(src, -xy[0], -xy[1], mErasePaint);
             dest.drawColor(0, PorterDuff.Mode.CLEAR);
-
-            float xScale = STROKE_WIDTH*2/(dest.getWidth());
-            float yScale = STROKE_WIDTH*2/(dest.getHeight());
-
-            scaleMatrix.reset();
-            scaleMatrix.preScale(1+xScale, 1+yScale, dest.getWidth()/2, dest.getHeight()/2);
             dest.setMatrix(id);
-            dest.drawBitmap(mask, scaleMatrix, mHolographicPaint);
-            dest.drawBitmap(mask, id, mErasePaint);
+            dest.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
             mask.recycle();
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0a1c8ff..a6a031a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3345,11 +3345,6 @@
             }
         }
 
-        public class Pid {
-            long mWakeSum;
-            long mWakeStart;
-        }
-
         /**
          * Retrieve the statistics object for a particular process, creating
          * if needed.
@@ -3364,6 +3359,10 @@
             return ps;
         }
 
+        public SparseArray<? extends Pid> getPidStats() {
+            return mPids;
+        }
+        
         public Pid getPidStatsLocked(int pid) {
             Pid p = mPids.get(pid);
             if (p == null) {
@@ -3588,6 +3587,11 @@
     }
     
     @Override
+    public long getHistoryBaseTime() {
+        return mHistoryBaseTime;
+    }
+    
+    @Override
     public int getStartCount() {
         return mStartCount;
     }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index cb0bdd3..65040fc 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -106,12 +106,13 @@
 	android_graphics_PixelFormat.cpp \
 	android/graphics/Picture.cpp \
 	android/graphics/PorterDuff.cpp \
-	android/graphics/LargeBitmap.cpp \
+	android/graphics/BitmapRegionDecoder.cpp \
 	android/graphics/Rasterizer.cpp \
 	android/graphics/Region.cpp \
 	android/graphics/Shader.cpp \
 	android/graphics/TextLayout.cpp \
 	android/graphics/Typeface.cpp \
+	android/graphics/Utils.cpp \
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
 	android_media_AudioRecord.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c9d7e7f..43e59f9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,7 +53,7 @@
 extern int register_android_os_Process(JNIEnv* env);
 extern int register_android_graphics_Bitmap(JNIEnv*);
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_LargeBitmap(JNIEnv*);
+extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
 extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_Interpolator(JNIEnv* env);
@@ -1245,7 +1245,7 @@
 
     REG_JNI(register_android_graphics_Bitmap),
     REG_JNI(register_android_graphics_BitmapFactory),
-    REG_JNI(register_android_graphics_LargeBitmap),
+    REG_JNI(register_android_graphics_BitmapRegionDecoder),
     REG_JNI(register_android_graphics_Camera),
     REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_ColorFilter),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 254d9a4..48539dc 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -10,6 +10,7 @@
 #include "SkUtils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "AutoDecodeCancel.h"
+#include "Utils.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Asset.h>
@@ -98,57 +99,6 @@
     }
 };
 
-class AssetStreamAdaptor : public SkStream {
-public:
-    AssetStreamAdaptor(Asset* a) : fAsset(a) {}
-    
-    virtual bool rewind() {
-        off_t pos = fAsset->seek(0, SEEK_SET);
-        if (pos == (off_t)-1) {
-            SkDebugf("----- fAsset->seek(rewind) failed\n");
-            return false;
-        }
-        return true;
-    }
-    
-    virtual size_t read(void* buffer, size_t size) {
-        ssize_t amount;
-        
-        if (NULL == buffer) {
-            if (0 == size) {  // caller is asking us for our total length
-                return fAsset->getLength();
-            }
-            // asset->seek returns new total offset
-            // we want to return amount that was skipped
-
-            off_t oldOffset = fAsset->seek(0, SEEK_CUR);
-            if (-1 == oldOffset) {
-                SkDebugf("---- fAsset->seek(oldOffset) failed\n");
-                return 0;
-            }
-            off_t newOffset = fAsset->seek(size, SEEK_CUR);
-            if (-1 == newOffset) {
-                SkDebugf("---- fAsset->seek(%d) failed\n", size);
-                return 0;
-            }
-            amount = newOffset - oldOffset;
-        } else {
-            amount = fAsset->read(buffer, size);
-            if (amount <= 0) {
-                SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
-            }
-        }
-        
-        if (amount < 0) {
-            amount = 0;
-        }
-        return amount;
-    }
-    
-private:
-    Asset*  fAsset;
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static inline int32_t validOrNeg1(bool isValid, int32_t value) {
@@ -200,12 +150,6 @@
             !env->GetBooleanField(options, gOptions_nativeAllocFieldID);
 }
 
-static jobject nullObjectReturn(const char msg[]) {
-    if (msg) {
-        SkDebugf("--- %s\n", msg);
-    }
-    return NULL;
-}
 
 static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
                                    int sampleSize, bool ditherImage) {
@@ -376,23 +320,6 @@
     return size;
 }
 
-/** Restore the file descriptor's offset in our destructor
- */
-class AutoFDSeek {
-public:
-    AutoFDSeek(int fd) : fFD(fd) {
-        fCurr = ::lseek(fd, 0, SEEK_CUR);
-    }
-    ~AutoFDSeek() {
-        if (fCurr >= 0) {
-            ::lseek(fFD, fCurr, SEEK_SET);
-        }
-    }
-private:
-    int     fFD;
-    off_t   fCurr;
-};
-
 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
                                           jobject fileDescriptor,
                                           jobject padding,
@@ -559,107 +486,6 @@
     }
 }
 
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream, bool isShareable) {
-    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
-    int width, height;
-    if (NULL == decoder) {
-        doThrowIOE(env, "Image format not supported");
-        return nullObjectReturn("SkImageDecoder::Factory returned null");
-    }
-
-    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
-    decoder->setAllocator(javaAllocator);
-    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
-    decoder->setReporter(javaMemoryReporter);
-    javaAllocator->unref();
-    javaMemoryReporter->unref();
-
-    if (!decoder->buildTileIndex(stream, &width, &height, isShareable)) {
-        char msg[1024];
-        snprintf(msg, 1023, "Image failed to decode using %s decoder", decoder->getFormatName());
-        doThrowIOE(env, msg);
-        return nullObjectReturn("decoder->buildTileIndex returned false");
-    }
-
-    SkLargeBitmap *bm = new SkLargeBitmap(decoder, width, height);
-
-    return GraphicsJNI::createLargeBitmap(env, bm);
-}
-
-static jobject nativeCreateLargeBitmapFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
-                                     int offset, int length, jboolean isShareable) {
-    AutoJavaByteArray ar(env, byteArray);
-    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
-    SkAutoUnref aur(stream);
-    if (isShareable) {
-        aur.detach();
-    }
-    return doBuildTileIndex(env, stream, isShareable);
-}
-
-static jobject nativeCreateLargeBitmapFromFileDescriptor(JNIEnv* env, jobject clazz,
-                                          jobject fileDescriptor, jboolean isShareable) {
-    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
-
-    jint descriptor = env->GetIntField(fileDescriptor,
-                                       gFileDescriptor_descriptor);
-    bool weOwnTheFD = false;
-
-    if (isShareable) {
-        int newFD = ::dup(descriptor);
-        if (-1 != newFD) {
-            weOwnTheFD = true;
-            descriptor = newFD;
-        }
-    }
-
-    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
-    SkAutoUnref aur(stream);
-    if (!stream->isValid()) {
-        return NULL;
-    }
-
-    if (isShareable) {
-        aur.detach();
-    }
-
-    /* Restore our offset when we leave, so we can be called more than once
-       with the same descriptor. This is only required if we didn't dup the
-       file descriptor, but it is OK to do it all the time.
-    */
-    AutoFDSeek as(descriptor);
-
-    return doBuildTileIndex(env, stream, isShareable);
-}
-
-static jobject nativeCreateLargeBitmapFromStream(JNIEnv* env, jobject clazz,
-                                  jobject is,       // InputStream
-                                  jbyteArray storage, // byte[]
-                                  jboolean isShareable) {
-    jobject largeBitmap = NULL;
-    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
-
-    if (stream) {
-        // for now we don't allow shareable with java inputstreams
-        largeBitmap = doBuildTileIndex(env, stream, false);
-        stream->unref();
-    }
-    return largeBitmap;
-}
-
-static jobject nativeCreateLargeBitmapFromAsset(JNIEnv* env, jobject clazz,
-                                 jint native_asset, // Asset
-                                 jboolean isShareable) {
-    SkStream* stream;
-    Asset* asset = reinterpret_cast<Asset*>(native_asset);
-    stream = new AssetStreamAdaptor(asset);
-    SkAutoUnref aur(stream);
-    if (isShareable) {
-        aur.detach();
-    }
-    return doBuildTileIndex(env, stream, isShareable);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gMethods[] = {
@@ -689,26 +515,6 @@
     },
 
     {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
-
-    {   "nativeCreateLargeBitmap",
-        "([BIIZ)Landroid/graphics/LargeBitmap;",
-        (void*)nativeCreateLargeBitmapFromByteArray
-    },
-
-    {   "nativeCreateLargeBitmap",
-        "(Ljava/io/InputStream;[BZ)Landroid/graphics/LargeBitmap;",
-        (void*)nativeCreateLargeBitmapFromStream
-    },
-
-    {   "nativeCreateLargeBitmap",
-        "(Ljava/io/FileDescriptor;Z)Landroid/graphics/LargeBitmap;",
-        (void*)nativeCreateLargeBitmapFromFileDescriptor
-    },
-
-    {   "nativeCreateLargeBitmap",
-        "(IZ)Landroid/graphics/LargeBitmap;",
-        (void*)nativeCreateLargeBitmapFromAsset
-    },
 };
 
 static JNINativeMethod gOptionsMethods[] = {
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
new file mode 100644
index 0000000..6a5be44
--- /dev/null
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BitmapRegionDecoder"
+
+#include "SkBitmap.h"
+#include "SkImageEncoder.h"
+#include "GraphicsJNI.h"
+#include "SkUtils.h"
+#include "SkTemplates.h"
+#include "SkPixelRef.h"
+#include "SkStream.h"
+#include "BitmapFactory.h"
+#include "AutoDecodeCancel.h"
+#include "SkBitmapRegionDecoder.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "Utils.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <binder/Parcel.h>
+#include <jni.h>
+#include <utils/Asset.h>
+
+static jclass gFileDescriptor_class;
+static jfieldID gFileDescriptor_descriptor;
+
+#if 0
+    #define TRACE_BITMAP(code)  code
+#else
+    #define TRACE_BITMAP(code)
+#endif
+
+using namespace android;
+
+static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream, bool isShareable) {
+    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
+    int width, height;
+    if (NULL == decoder) {
+        doThrowIOE(env, "Image format not supported");
+        return nullObjectReturn("SkImageDecoder::Factory returned null");
+    }
+
+    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
+    decoder->setAllocator(javaAllocator);
+    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
+    decoder->setReporter(javaMemoryReporter);
+    javaAllocator->unref();
+    javaMemoryReporter->unref();
+
+    if (!decoder->buildTileIndex(stream, &width, &height, isShareable)) {
+        char msg[1024];
+        snprintf(msg, 1023, "Image failed to decode using %s decoder", decoder->getFormatName());
+        doThrowIOE(env, msg);
+        return nullObjectReturn("decoder->buildTileIndex returned false");
+    }
+
+    SkBitmapRegionDecoder *brd = new SkBitmapRegionDecoder(decoder, width, height);
+
+    return GraphicsJNI::createBitmapRegionDecoder(env, brd);
+}
+
+static jobject nativeNewInstanceFromByteArray(JNIEnv* env,
+        jobject, jbyteArray byteArray, int offset, int length,
+        jboolean isShareable) {
+    AutoJavaByteArray ar(env, byteArray);
+    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
+    SkAutoUnref aur(stream);
+    if (isShareable) {
+        aur.detach();
+    }
+    return doBuildTileIndex(env, stream, isShareable);
+}
+
+static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env,
+        jobject clazz, jobject fileDescriptor, jboolean isShareable) {
+    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
+
+    jint descriptor = env->GetIntField(fileDescriptor,
+                                       gFileDescriptor_descriptor);
+    bool weOwnTheFD = false;
+
+    if (isShareable) {
+        int newFD = ::dup(descriptor);
+        if (-1 != newFD) {
+            weOwnTheFD = true;
+            descriptor = newFD;
+        }
+    }
+
+    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
+    SkAutoUnref aur(stream);
+    if (!stream->isValid()) {
+        return NULL;
+    }
+
+    if (isShareable) {
+        aur.detach();
+    }
+
+    // Restore our offset when we leave, so we can be called more than once
+    // with the same descriptor. This is only required if we didn't dup the
+    // file descriptor, but it is OK to do it all the time.
+    AutoFDSeek as(descriptor);
+
+    return doBuildTileIndex(env, stream, isShareable);
+}
+
+static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
+                                  jobject is,       // InputStream
+                                  jbyteArray storage, // byte[]
+                                  jboolean isShareable) {
+    jobject BitmapRegionDecoder = NULL;
+    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
+
+    if (stream) {
+        // for now we don't allow shareable with java inputstreams
+        BitmapRegionDecoder = doBuildTileIndex(env, stream, false);
+        stream->unref();
+    }
+    return BitmapRegionDecoder;
+}
+
+static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
+                                 jint native_asset, // Asset
+                                 jboolean isShareable) {
+    SkStream* stream;
+    Asset* asset = reinterpret_cast<Asset*>(native_asset);
+    stream = new AssetStreamAdaptor(asset);
+    SkAutoUnref aur(stream);
+    if (isShareable) {
+        aur.detach();
+    }
+    return doBuildTileIndex(env, stream, isShareable);
+}
+
+/*
+ * nine patch not supported
+ *
+ * purgeable not supported
+ * reportSizeToVM not supported
+ */
+static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
+        int start_x, int start_y, int width, int height, jobject options) {
+    SkImageDecoder *decoder = brd->getDecoder();
+    int sampleSize = 1;
+    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+    bool doDither = true;
+
+    if (NULL != options) {
+        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
+        // initialize these, in case we fail later on
+        env->SetIntField(options, gOptions_widthFieldID, -1);
+        env->SetIntField(options, gOptions_heightFieldID, -1);
+        env->SetObjectField(options, gOptions_mimeFieldID, 0);
+
+        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
+        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+    }
+
+    decoder->setDitherImage(doDither);
+    SkBitmap*           bitmap = new SkBitmap;
+    SkAutoTDelete<SkBitmap>       adb(bitmap);
+    AutoDecoderCancel   adc(options, decoder);
+
+    // To fix the race condition in case "requestCancelDecode"
+    // happens earlier than AutoDecoderCancel object is added
+    // to the gAutoDecoderCancelMutex linked list.
+    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
+        return nullObjectReturn("gOptions_mCancelID");;
+    }
+
+    SkIRect region;
+    region.fLeft = start_x;
+    region.fTop = start_y;
+    region.fRight = start_x + width;
+    region.fBottom = start_y + height;
+
+    if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
+        return nullObjectReturn("decoder->decodeRegion returned false");
+    }
+
+    // update options (if any)
+    if (NULL != options) {
+        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
+        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
+        // TODO: set the mimeType field with the data from the codec.
+        // but how to reuse a set of strings, rather than allocating new one
+        // each time?
+        env->SetObjectField(options, gOptions_mimeFieldID,
+                            getMimeTypeString(env, decoder->getFormat()));
+    }
+
+    // detach bitmap from its autotdeleter, since we want to own it now
+    adb.detach();
+
+    SkPixelRef* pr;
+    pr = bitmap->pixelRef();
+    // promise we will never change our pixels (great for sharing and pictures)
+    pr->setImmutable();
+    // now create the java bitmap
+    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+}
+
+static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+    return brd->getHeight();
+}
+
+static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+    return brd->getWidth();
+}
+
+static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+    delete brd;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+    {   "nativeDecodeRegion",
+        "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        (void*)nativeDecodeRegion},
+
+    {   "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
+
+    {   "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
+
+    {   "nativeClean", "(I)V", (void*)nativeClean},
+
+    {   "nativeNewInstance",
+        "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
+        (void*)nativeNewInstanceFromByteArray
+    },
+
+    {   "nativeNewInstance",
+        "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
+        (void*)nativeNewInstanceFromStream
+    },
+
+    {   "nativeNewInstance",
+        "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
+        (void*)nativeNewInstanceFromFileDescriptor
+    },
+
+    {   "nativeNewInstance",
+        "(IZ)Landroid/graphics/BitmapRegionDecoder;",
+        (void*)nativeNewInstanceFromAsset
+    },
+};
+
+#define kClassPathName  "android/graphics/BitmapRegionDecoder"
+
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
+{
+    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+            gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 578de6f..b520c30 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -169,8 +169,8 @@
 static jclass   gBitmapConfig_class;
 static jfieldID gBitmapConfig_nativeInstanceID;
 
-static jclass   gLargeBitmap_class;
-static jmethodID gLargeBitmap_constructorMethodID;
+static jclass   gBitmapRegionDecoder_class;
+static jmethodID gBitmapRegionDecoder_constructorMethodID;
 
 static jclass   gCanvas_class;
 static jfieldID gCanvas_nativeInstanceID;
@@ -377,17 +377,18 @@
     }
     return obj;
 }
-jobject GraphicsJNI::createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap)
+
+jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
 {
     SkASSERT(bitmap != NULL);
 
-    jobject obj = env->AllocObject(gLargeBitmap_class);
+    jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
     if (hasException(env)) {
         obj = NULL;
         return obj;
     }
     if (obj) {
-        env->CallVoidMethod(obj, gLargeBitmap_constructorMethodID, (jint)bitmap);
+        env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
         if (hasException(env)) {
             obj = NULL;
         }
@@ -613,8 +614,8 @@
     gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
                                             "(IZ[BI)V");
 
-    gLargeBitmap_class = make_globalref(env, "android/graphics/LargeBitmap");
-    gLargeBitmap_constructorMethodID = env->GetMethodID(gLargeBitmap_class, "<init>", "(I)V");
+    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
+    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
 
     gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
     gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
@@ -654,4 +655,3 @@
 
     return 0;
 }
-
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 1a43a3e..d0f9125 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -4,7 +4,7 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkBitmap.h"
-#include "../images/SkLargeBitmap.h"
+#include "../images/SkBitmapRegionDecoder.h"
 #include "../images/SkImageDecoder.h"
 #include <jni.h>
 
@@ -56,7 +56,7 @@
     
     static jobject createRegion(JNIEnv* env, SkRegion* region);
 
-    static jobject createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap);
+    static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
 
     /** Set a pixelref for the bitmap (needs setConfig to already be called)
         Returns true on success. If it returns false, then it failed, and the
@@ -181,4 +181,3 @@
     do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0)
 
 #endif
-
diff --git a/core/jni/android/graphics/LargeBitmap.cpp b/core/jni/android/graphics/LargeBitmap.cpp
deleted file mode 100644
index 4cf5dfa..0000000
--- a/core/jni/android/graphics/LargeBitmap.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#define LOG_TAG "LargeBitmap"
-
-#include "SkBitmap.h"
-#include "SkImageEncoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-#include "SkUnPreMultiply.h"
-#include "SkUtils.h"
-#include "SkTemplates.h"
-#include "SkPixelRef.h"
-#include "BitmapFactory.h"
-#include "AutoDecodeCancel.h"
-#include "SkLargeBitmap.h"
-
-#include <binder/Parcel.h>
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
-
-static jobject nullObjectReturn(const char msg[]) {
-    if (msg) {
-        SkDebugf("--- %s\n", msg);
-    }
-    return NULL;
-}
-
-/*
- * nine patch not supported
- *
- * purgeable not supported
- * reportSizeToVM not supported
- */
-static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkLargeBitmap *bm,
-        int start_x, int start_y, int width, int height, jobject options) {
-    SkImageDecoder *decoder = bm->getDecoder();
-    int sampleSize = 1;
-    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
-    bool doDither = true;
-
-    if (NULL != options) {
-        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
-        // initialize these, in case we fail later on
-        env->SetIntField(options, gOptions_widthFieldID, -1);
-        env->SetIntField(options, gOptions_heightFieldID, -1);
-        env->SetObjectField(options, gOptions_mimeFieldID, 0);
-
-        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
-        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
-        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
-    }
-
-    decoder->setDitherImage(doDither);
-    SkBitmap*           bitmap = new SkBitmap;
-    SkAutoTDelete<SkBitmap>       adb(bitmap);
-    AutoDecoderCancel   adc(options, decoder);
-
-    // To fix the race condition in case "requestCancelDecode"
-    // happens earlier than AutoDecoderCancel object is added
-    // to the gAutoDecoderCancelMutex linked list.
-    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
-        return nullObjectReturn("gOptions_mCancelID");;
-    }
-
-    SkIRect region;
-    region.fLeft = start_x;
-    region.fTop = start_y;
-    region.fRight = start_x + width;
-    region.fBottom = start_y + height;
-
-    if (!bm->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
-        return nullObjectReturn("decoder->decodeRegion returned false");
-    }
-
-    // update options (if any)
-    if (NULL != options) {
-        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
-        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
-        // TODO: set the mimeType field with the data from the codec.
-        // but how to reuse a set of strings, rather than allocating new one
-        // each time?
-        env->SetObjectField(options, gOptions_mimeFieldID,
-                            getMimeTypeString(env, decoder->getFormat()));
-    }
-
-    // detach bitmap from its autotdeleter, since we want to own it now
-    adb.detach();
-
-    SkPixelRef* pr;
-    pr = bitmap->pixelRef();
-    // promise we will never change our pixels (great for sharing and pictures)
-    pr->setImmutable();
-    // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
-}
-
-static int nativeGetHeight(JNIEnv* env, jobject, SkLargeBitmap *bm) {
-    return bm->getHeight();
-}
-
-static int nativeGetWidth(JNIEnv* env, jobject, SkLargeBitmap *bm) {
-    return bm->getWidth();
-}
-
-static void nativeClean(JNIEnv* env, jobject, SkLargeBitmap *bm) {
-    delete bm;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gLargeBitmapMethods[] = {
-    {   "nativeDecodeRegion",
-        "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
-        (void*)nativeDecodeRegion},
-    {   "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
-    {   "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
-    {   "nativeClean", "(I)V", (void*)nativeClean},
-};
-
-#define kClassPathName  "android/graphics/LargeBitmap"
-
-int register_android_graphics_LargeBitmap(JNIEnv* env);
-int register_android_graphics_LargeBitmap(JNIEnv* env)
-{
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-                                gLargeBitmapMethods, SK_ARRAY_COUNT(gLargeBitmapMethods));
-}
-
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
new file mode 100644
index 0000000..b6ead19
--- /dev/null
+++ b/core/jni/android/graphics/Utils.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include "Utils.h"
+#include "SkUtils.h"
+
+using namespace android;
+
+bool AssetStreamAdaptor::rewind() {
+    off_t pos = fAsset->seek(0, SEEK_SET);
+    if (pos == (off_t)-1) {
+        SkDebugf("----- fAsset->seek(rewind) failed\n");
+        return false;
+    }
+    return true;
+}
+
+size_t AssetStreamAdaptor::read(void* buffer, size_t size) {
+    ssize_t amount;
+
+    if (NULL == buffer) {
+        if (0 == size) {  // caller is asking us for our total length
+            return fAsset->getLength();
+        }
+        // asset->seek returns new total offset
+        // we want to return amount that was skipped
+
+        off_t oldOffset = fAsset->seek(0, SEEK_CUR);
+        if (-1 == oldOffset) {
+            SkDebugf("---- fAsset->seek(oldOffset) failed\n");
+            return 0;
+        }
+        off_t newOffset = fAsset->seek(size, SEEK_CUR);
+        if (-1 == newOffset) {
+            SkDebugf("---- fAsset->seek(%d) failed\n", size);
+            return 0;
+        }
+        amount = newOffset - oldOffset;
+    } else {
+        amount = fAsset->read(buffer, size);
+        if (amount <= 0) {
+            SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
+        }
+    }
+
+    if (amount < 0) {
+        amount = 0;
+    }
+    return amount;
+}
+
+jobject android::nullObjectReturn(const char msg[]) {
+    if (msg) {
+        SkDebugf("--- %s\n", msg);
+    }
+    return NULL;
+}
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
new file mode 100644
index 0000000..2de41a1
--- /dev/null
+++ b/core/jni/android/graphics/Utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILS_DEFINED
+#define UTILS_DEFINED
+
+#include "SkStream.h"
+
+#include "android_util_Binder.h"
+
+#include <jni.h>
+#include <utils/Asset.h>
+
+namespace android {
+
+class AssetStreamAdaptor : public SkStream {
+public:
+    AssetStreamAdaptor(Asset* a) : fAsset(a) {}
+    virtual bool rewind();
+    virtual size_t read(void* buffer, size_t size);
+
+private:
+    Asset*  fAsset;
+};
+
+
+/** Restore the file descriptor's offset in our destructor
+ */
+class AutoFDSeek {
+public:
+    AutoFDSeek(int fd) : fFD(fd) {
+        fCurr = ::lseek(fd, 0, SEEK_CUR);
+    }
+    ~AutoFDSeek() {
+        if (fCurr >= 0) {
+            ::lseek(fFD, fCurr, SEEK_SET);
+        }
+    }
+private:
+    int     fFD;
+    off_t   fCurr;
+};
+
+jobject nullObjectReturn(const char msg[]);
+
+}; // namespace android
+
+#endif
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 0932473a..2517a8a 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -127,12 +127,13 @@
     close(mDispatchKeyWrite);
 }
 
-void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) {
+void AInputQueue::attachLooper(ALooper* looper, int ident,
+        ALooper_callbackFunc* callback, void* data) {
     mPollLoop = static_cast<android::PollLoop*>(looper);
     mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
-            POLLIN, callback, data);
+            ident, POLLIN, callback, data);
     mPollLoop->setLooperCallback(mDispatchKeyRead,
-            POLLIN, callback, data);
+            ident, POLLIN, callback, data);
 }
 
 void AInputQueue::detachLooper() {
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 4b3f1c0..36e9089 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -593,6 +593,9 @@
         case SQLITE_MISMATCH:
            exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
            break;
+        case SQLITE_UNCLOSED:
+           exceptionClass = "android/database/sqlite/SQLiteUnfinalizedObjectsException";
+           break;
         default:
            exceptionClass = "android/database/sqlite/SQLiteException";
            break;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c99271..7dfb716 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -261,8 +261,7 @@
             continue;
         }
      
-        if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                                            SP_BACKGROUND : SP_FOREGROUND)) {
+        if (androidSetThreadSchedulingGroup(t_pid, grp) != NO_ERROR) {
             signalExceptionForGroupError(env, clazz, errno);
             break;
         }
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1951d14..8594027 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1265,7 +1265,13 @@
   <public type="drawable" name="presence_audio_online" id="0x010800b1" />
   <public-padding type="drawable" name="kraken_resource_pad" end="0x01080100" />
 
+  <public type="style" name="TextAppearance.StatusBar.Title" id="0x01030065" />
+  <public type="style" name="TextAppearance.StatusBar.Icon" id="0x01030066" />
+  <public type="style" name="TextAppearance.StatusBar.EventContent" id="0x01030067" />
+  <public type="style" name="TextAppearance.StatusBar.EventContent.Title" id="0x01030068" />
+
   <public-padding type="style" name="kraken_resource_pad" end="0x01030090" />
+
   <public-padding type="string" name="kraken_resource_pad" end="0x01040020" />
   <public-padding type="integer" name="kraken_resource_pad" end="0x010e0010" />
   <public-padding type="layout" name="kraken_resource_pad" end="0x01090020" />
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
new file mode 100644
index 0000000..cd2005d
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.database.sqlite;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabaseTest.ClassToTestSqlCompilationAndCaching;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.File;
+
+public class SQLiteUnfinalizedExceptionTest extends AndroidTestCase {
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+    private static final String TABLE_NAME = "testCursor";
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+        mDatabaseFile = new File(dbDir, "UnfinalizedExceptionTest.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    @SmallTest
+    public void testUnfinalizedExceptionNotExcpected() {
+        mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+        // the above statement should be in SQLiteDatabase.mPrograms
+        // and should automatically be finalized when database is closed
+        mDatabase.lock();
+        try {
+            mDatabase.closeDatabase();
+        } finally {
+            mDatabase.unlock();
+        }
+    }
+
+    @SmallTest
+    public void testUnfinalizedException() {
+        mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+        mDatabase.lock();
+        mDatabase.closePendingStatements(); // clears the above from finalizer queue in mdatabase
+        mDatabase.unlock();
+        ClassToTestSqlCompilationAndCaching.create(mDatabase, "select * from "  + TABLE_NAME);
+        // since the above is NOT closed, closing database should fail
+        mDatabase.lock();
+        try {
+            mDatabase.closeDatabase();
+            fail("exception expected");
+        } catch (SQLiteUnfinalizedObjectsException e) {
+            // expected
+        } finally {
+            mDatabase.unlock();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 60c3c76..c8ad60d 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -285,6 +285,7 @@
         assertEquals("d", uri.getQueryParameter("c"));
     }
 
+    // http://b/2337042
     @SmallTest
     public void testHostWithTrailingDot() {
         Uri uri = Uri.parse("http://google.com./b/c/g");
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 7ca1e62..f0af35d 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -22,10 +22,19 @@
 
 public class WebAddressTest extends TestCase {
 
+    // http://b/2337042
     @SmallTest
     public void testHostWithTrailingDot() {
         WebAddress webAddress = new WebAddress("http://google.com./b/c/g");
         assertEquals("google.com.", webAddress.mHost);
         assertEquals("/b/c/g", webAddress.mPath);
     }
+
+    // http://b/1011602
+    @SmallTest
+    public void testPathWithoutLeadingSlash() {
+        WebAddress webAddress = new WebAddress("http://www.myspace.com?si=1");
+        assertEquals("www.myspace.com", webAddress.mHost);
+        assertEquals("/?si=1", webAddress.mPath);
+    }
 }
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index f22d2d3..56872a7 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -42,188 +42,39 @@
 
 <h2 id="optimize_judiciously">Optimize Judiciously</h2>
 
-<p>As you get started thinking about how to design your application, and as
-you write it, consider
-the cautionary points about optimization that Josh Bloch makes in his book
-<em>Effective Java</em>. Here's "Item 47: Optimize Judiciously", excerpted from
-the latest edition of the book with permission. Although Josh didn't have
-Android application development in mind when writing this section &mdash; for
-example, the <code style="color:black">java.awt.Component</code> class
-referenced is not available in Android, and Android uses the
-Dalvik VM, rather than a standard JVM &mdash; his points are still valid. </p>
+<p>This document is about Android-specific micro-optimization, so it assumes
+that you've already used profiling to work out exactly what code needs to be
+optimized, and that you already have a way to measure the effect (good or bad)
+of any changes you make. You only have so much engineering time to invest, so
+it's important to know you're spending it wisely.
 
-<blockquote>
+<p>(See <a href="#closing_notes">Closing Notes</a> for more on profiling and
+writing effective benchmarks.)
 
-<p>There are three aphorisms concerning optimization that everyone should know.
-They are perhaps beginning to suffer from overexposure, but in case you aren't
-yet familiar with them, here they are:</p>
+<p>This document also assumes that you made the best decisions about data
+structures and algorithms, and that you've also considered the future
+performance consequences of your API decisions. Using the right data
+structures and algorithms will make more difference than any of the advice
+here, and considering the performance consequences of your API decisions will
+make it easier to switch to better implementations later (this is more
+important for library code than for application code).
 
-<div style="padding-left:3em;padding-right:4em;">
+<p>(If you need that kind of advice, see Josh Bloch's <em>Effective Java</em>,
+item 47.)</p>
 
-<p style="margin-bottom:.5em;">More computing sins are committed in the name of
-efficiency (without necessarily achieving it) than for any other single
-reason&mdash;including blind stupidity.</p>
-<p>&mdash;William A. Wulf <span style="font-size:80%;"><sup>1</sup></span></p>
+<p>One of the trickiest problems you'll face when micro-optimizing an Android
+app is that your app is pretty much guaranteed to be running on multiple
+hardware platforms. Different versions of the VM running on different
+processors running at different speeds. It's not even generally the case
+that you can simply say "device X is a factor F faster/slower than device Y",
+and scale your results from one device to others. In particular, measurement
+on the emulator tells you very little about performance on any device. There
+are also huge differences between devices with and without a JIT: the "best"
+code for a device with a JIT is not always the best code for a device
+without.</p>
 
-<p style="margin-bottom:.5em;">We should forget about small efficiencies, say
-about 97% of the time: premature optimization is the root of all evil. </p>
-<p>&mdash;Donald E. Knuth <span style="font-size:80%;"><sup>2</sup></span></p>
-
-
-<p style="margin-bottom:.5em;">We follow two rules in the matter of optimization:</p>
-<ul style="margin-bottom:0">
-<li>Rule 1. Don't do it.</li>
-<li>Rule 2 (for experts only). Don't do it yet &mdash; that is, not until you have a
-perfectly clear and unoptimized solution. </li>
-</ul>
-<p>&mdash;M. A. Jackson <span style="font-size:80%;"><sup>3</sup></span></p>
-</div>
-
-<p>All of these aphorisms predate the Java programming language by two decades.
-They tell a deep truth about optimization: it is easy to do more harm than good,
-especially if you optimize prematurely. In the process, you may produce software
-that is neither fast nor correct and cannot easily be fixed.</p>
-
-<p>Don't sacrifice sound architectural principles for performance.
-<strong>Strive to write good programs rather than fast ones.</strong> If a good
-program is not fast enough, its architecture will allow it to be optimized. Good
-programs embody the principle of <em>information hiding</em>: where possible,
-they localize design decisions within individual modules, so individual
-decisions can be changed without affecting the remainder of the system (Item
-13).</p>
-
-<p>This does <em>not</em> mean that you can ignore performance concerns until
-your program is complete. Implementation problems can be fixed by later
-optimization, but pervasive architectural flaws that limit performance can be
-impossible to fix without rewriting the system. Changing a fundamental facet of
-your design after the fact can result in an ill-structured system that is
-difficult to maintain and evolve. Therefore you must think about performance
-during the design process.</p>
-
-<p><strong>Strive to avoid design decisions that limit performance.</strong> The
-components of a design that are most difficult to change after the fact are
-those specifying interactions between modules and with the outside world. Chief
-among these design components are APIs, wire-level protocols, and persistent
-data formats. Not only are these design components difficult or impossible to
-change after the fact, but all of them can place significant limitations on the
-performance that a system can ever achieve.</p>
-
-<p><strong>Consider the performance consequences of your API design
-decisions.</strong> Making a public type mutable may require a lot of needless
-defensive copying (Item 39). Similarly, using inheritance in a public class
-where composition would have been appropriate ties the class forever to its
-superclass, which can place artificial limits on the performance of the subclass
-(Item 16). As a final example, using an implementation type rather than an
-interface in an API ties you to a specific implementation, even though faster
-implementations may be written in the future (Item 52).</p>
-
-<p>The effects of API design on performance are very real. Consider the <code
-style="color:black">getSize</code> method in the <code
-style="color:black">java.awt.Component</code> class. The decision that this
-performance-critical method was to return a <code
-style="color:black">Dimension</code> instance, coupled with the decision that
-<code style="color:black">Dimension</code> instances are mutable, forces any
-implementation of this method to allocate a new <code
-style="color:black">Dimension</code> instance on every invocation. Even though
-allocating small objects is inexpensive on a modern VM, allocating millions of
-objects needlessly can do real harm to performance.</p>
-
-<p>In this case, several alternatives existed. Ideally, <code
-style="color:black">Dimension</code> should have been immutable (Item 15);
-alternatively, the <code style="color:black">getSize</code> method could have
-been replaced by two methods returning the individual primitive components of a
-<code style="color:black">Dimension</code> object. In fact, two such methods
-were added to the Component API in the 1.2 release for performance reasons.
-Preexisting client code, however, still uses the <code
-style="color:black">getSize</code> method and still suffers the performance
-consequences of the original API design decisions.</p>
-
-<p>Luckily, it is generally the case that good API design is consistent with
-good performance. <strong>It is a very bad idea to warp an API to achieve good
-performance.</strong> The performance issue that caused you to warp the API may
-go away in a future release of the platform or other underlying software, but
-the warped API and the support headaches that come with it will be with you for
-life.</p>
-
-<p>Once you've carefully designed your program and produced a clear, concise,
-and well-structured implementation, <em>then</em> it may be time to consider
-optimization, assuming you're not already satisfied with the performance of the
-program.</p>
-
-<p>Recall that Jackson's two rules of optimization were "Don't do it," and "(for
-experts only). Don't do it yet." He could have added one more: <strong>measure
-performance before and after each attempted optimization.</strong> You may be
-surprised by what you find. Often, attempted optimizations have no measurable
-effect on performance; sometimes, they make it worse. The main reason is that
-it's difficult to guess where your program is spending its time. The part of the
-program that you think is slow may not be at fault, in which case you'd be
-wasting your time trying to optimize it. Common wisdom says that programs spend
-80 percent of their time in 20 percent of their code.</p>
-
-<p>Profiling tools can help you decide where to focus your optimization efforts.
-Such tools give you runtime information, such as roughly how much time each
-method is consuming and how many times it is invoked. In addition to focusing
-your tuning efforts, this can alert you to the need for algorithmic changes. If
-a quadratic (or worse) algorithm lurks inside your program, no amount of tuning
-will fix the problem. You must replace the algorithm with one that is more
-efficient. The more code in the system, the more important it is to use a
-profiler. It's like looking for a needle in a haystack: the bigger the haystack,
-the more useful it is to have a metal detector. The JDK comes with a simple
-profiler and modern IDEs provide more sophisticated profiling tools.</p>
-
-<p>The need to measure the effects of attempted optimization is even greater on
-the Java platform than on more traditional platforms, because the Java
-programming language does not have a strong <em>performance model</em>. The
-relative costs of the various primitive operations are not well defined. The
-"semantic gap" between what the programmer writes and what the CPU executes is
-far greater than in traditional statically compiled languages, which makes it
-very difficult to reliably predict the performance consequences of any
-optimization. There are plenty of performance myths floating around that turn
-out to be half-truths or outright lies.</p>
-
-<p>Not only is Java's performance model ill-defined, but it varies from JVM
-implementation to JVM implementation, from release to release, and from
-processor to processor. If you will be running your program on multiple JVM
-implementations or multiple hardware platforms, it is important that you measure
-the effects of your optimization on each. Occasionally you may be forced to make
-trade-offs between performance on different JVM implementations or hardware
-platforms.</p>
-
-<p>To summarize, do not strive to write fast programs &mdash; strive to write
-good ones; speed will follow. Do think about performance issues while you're
-designing systems and especially while you're designing APIs, wire-level
-protocols, and persistent data formats. When you've finished building the
-system, measure its performance. If it's fast enough, you're done. If not,
-locate the source of the problems with the aid of a profiler, and go to work
-optimizing the relevant parts of the system. The first step is to examine your
-choice of algorithms: no amount of low-level optimization can make up for a poor
-choice of algorithm. Repeat this process as necessary, measuring the performance
-after every change, until you're satisfied.</p>
-
-<p>&mdash;Excerpted from Josh Bloch's <em>Effective Java</em>, Second Ed.
-(Addison-Wesley, 2008).</em></p>
-
-<p style="font-size:80%;margin-bottom:0;"><sup>1</sup> Wulf, W. A Case Against
-the GOTO. <em>Proceedings of the 25th ACM National
-Conference</em> 2 (1972): 791–797.</p>
-<p style="font-size:80%;margin-bottom:0;"><sup>2</sup> Knuth, Donald. Structured
-Programming with go to Statements. <em>Computing
-Surveys 6</em> (1974): 261–301.</p>
-<p style="font-size:80%"><sup>3</sup> Jackson, M. A. <em>Principles of Program
-Design</em>, Academic Press, London, 1975.
-ISBN: 0123790506.</p>
-
-</blockquote>
-
-<p>One of the trickiest problems you'll face when micro-optimizing Android
-apps is that the "if you will be running your program on ... multiple hardware
-platforms" clause above is always true. And it's not even generally the case
-that you can say "device X is a factor F faster/slower than device Y".
-This is especially true if one of the devices is the emulator, or one of the
-devices has a JIT. If you want to know how your app performs on a given device,
-you need to test it on that device. Drawing conclusions from the emulator is
-particularly dangerous, as is attempting to compare JIT versus non-JIT
-performance: the performance <em>profiles</em> can differ wildly.</p>
+<p>If you want to know how your app performs on a given device, you need to
+test on that device.</p>
 
 <a name="object_creation"></a>
 <h2>Avoid Creating Objects</h2>
@@ -566,3 +417,11 @@
 not measuring what you think you're measuring (because, say, the VM has
 managed to optimize all your code away). We highly recommend you use Caliper
 to run your own microbenchmarks.</p>
+
+<p>You may also find
+<a href="{@docRoot}guide/developing/tools/traceview.html">Traceview</a> useful
+for profiling, but it's important to realize that it currently disables the JIT,
+which may cause it to misattribute time to code that the JIT may be able to win
+back. It's especially important after making changes suggested by Traceview
+data to ensure that the resulting code actually runs faster when run without
+Traceview.
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
new file mode 100644
index 0000000..bc92b05
--- /dev/null
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -0,0 +1,270 @@
+/* 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.graphics;
+
+import android.content.res.AssetManager;
+import android.os.MemoryFile;
+
+import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * BitmapRegionDecoder can be used to decode a rectangle region from an image.
+ * BitmapRegionDecoder is particularly useful when an original image is large and
+ * you only need parts of the image.
+ *
+ * <p>To create a BitmapRegionDecoder, call newInstance(...).
+ * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
+ * to get a decoded Bitmap of the specified region.
+ *
+ * @hide
+ */
+public final class BitmapRegionDecoder {
+    private int mNativeBitmapRegionDecoder;
+    private boolean mRecycled;
+
+    /**
+     * Create a BitmapRegionDecoder from the specified byte array.
+     * Currently only the Jpeg format is supported.
+     *
+     * @param data byte array of compressed image data.
+     * @param offset offset into data for where the decoder should begin
+     *               parsing.
+     * @param length the number of bytes, beginning at offset, to parse
+     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+     *                    shallow reference to the input. If this is false,
+     *                    then the BitmapRegionDecoder will explicitly make a copy of the
+     *                    input data, and keep that. Even if sharing is allowed,
+     *                    the implementation may still decide to make a deep
+     *                    copy of the input data. If an image is progressively encoded,
+     *                    allowing sharing may degrade the decoding speed.
+     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+     * @throws IOException if the image format is not supported or can not be decoded.
+     */
+    public static BitmapRegionDecoder newInstance(byte[] data,
+            int offset, int length, boolean isShareable) throws IOException {
+        if ((offset | length) < 0 || data.length < offset + length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return nativeNewInstance(data, offset, length, isShareable);
+    }
+
+    /**
+     * Create a BitmapRegionDecoder from the file descriptor.
+     * The position within the descriptor will not be changed when
+     * this returns, so the descriptor can be used again as is.
+     * Currently only the Jpeg format is supported.
+     *
+     * @param fd The file descriptor containing the data to decode
+     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+     *                    shallow reference to the input. If this is false,
+     *                    then the BitmapRegionDecoder will explicitly make a copy of the
+     *                    input data, and keep that. Even if sharing is allowed,
+     *                    the implementation may still decide to make a deep
+     *                    copy of the input data. If an image is progressively encoded,
+     *                    allowing sharing may degrade the decoding speed.
+     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+     * @throws IOException if the image format is not supported or can not be decoded.
+     */
+    public static BitmapRegionDecoder newInstance(
+            FileDescriptor fd, boolean isShareable) throws IOException {
+        if (MemoryFile.isMemoryFile(fd)) {
+            int mappedlength = MemoryFile.getSize(fd);
+            MemoryFile file = new MemoryFile(fd, mappedlength, "r");
+            InputStream is = file.getInputStream();
+            return newInstance(is, isShareable);
+        }
+        return nativeNewInstance(fd, isShareable);
+    }
+
+    /**
+     * Create a BitmapRegionDecoder from an input stream.
+     * The stream's position will be where ever it was after the encoded data
+     * was read.
+     * Currently only the Jpeg format is supported.
+     *
+     * @param is The input stream that holds the raw data to be decoded into a
+     *           BitmapRegionDecoder.
+     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+     *                    shallow reference to the input. If this is false,
+     *                    then the BitmapRegionDecoder will explicitly make a copy of the
+     *                    input data, and keep that. Even if sharing is allowed,
+     *                    the implementation may still decide to make a deep
+     *                    copy of the input data. If an image is progressively encoded,
+     *                    allowing sharing may degrade the decoding speed.
+     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+     * @throws IOException if the image format is not supported or can not be decoded.
+     */
+    public static BitmapRegionDecoder newInstance(InputStream is,
+            boolean isShareable) throws IOException {
+        // we need mark/reset to work properly in JNI
+
+        if (!is.markSupported()) {
+            is = new BufferedInputStream(is, 16 * 1024);
+        }
+
+        if (is instanceof AssetManager.AssetInputStream) {
+            return nativeNewInstance(
+                    ((AssetManager.AssetInputStream) is).getAssetInt(),
+                    isShareable);
+        } else {
+            // pass some temp storage down to the native code. 1024 is made up,
+            // but should be large enough to avoid too many small calls back
+            // into is.read(...).
+            byte [] tempStorage = new byte[16 * 1024];
+            return nativeNewInstance(is, tempStorage, isShareable);
+        }
+    }
+
+    /**
+     * Create a BitmapRegionDecoder from a file path.
+     * Currently only the Jpeg format is supported.
+     *
+     * @param pathName complete path name for the file to be decoded.
+     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+     *                    shallow reference to the input. If this is false,
+     *                    then the BitmapRegionDecoder will explicitly make a copy of the
+     *                    input data, and keep that. Even if sharing is allowed,
+     *                    the implementation may still decide to make a deep
+     *                    copy of the input data. If an image is progressively encoded,
+     *                    allowing sharing may degrade the decoding speed.
+     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+     * @throws IOException if the image format is not supported or can not be decoded.
+     */
+    public static BitmapRegionDecoder newInstance(String pathName,
+            boolean isShareable) throws IOException {
+        BitmapRegionDecoder decoder = null;
+        InputStream stream = null;
+
+        try {
+            stream = new FileInputStream(pathName);
+            decoder = newInstance(stream, isShareable);
+        } finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    // do nothing here
+                }
+            }
+        }
+        return decoder;
+    }
+
+    /*  Private constructor that must receive an already allocated native
+        region decoder int (pointer).
+
+        This can be called from JNI code.
+    */
+    private BitmapRegionDecoder(int decoder) {
+        mNativeBitmapRegionDecoder = decoder;
+        mRecycled = false;
+    }
+
+    /**
+     * Decodes a rectangle region in the image specified by rect.
+     *
+     * @param rect The rectangle that specified the region to be decode.
+     * @param options null-ok; Options that control downsampling.
+     *             inPurgeable is not supported.
+     * @return The decoded bitmap, or null if the image data could not be
+     *         decoded.
+     */
+    public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
+        checkRecycled("decodeRegion called on recycled region decoder");
+        if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
+                || rect.bottom > getHeight())
+            throw new IllegalArgumentException("rectangle is not inside the image");
+        return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
+                rect.right - rect.left, rect.bottom - rect.top, options);
+    }
+
+    /** Returns the original image's width */
+    public int getWidth() {
+        checkRecycled("getWidth called on recycled region decoder");
+        return nativeGetWidth(mNativeBitmapRegionDecoder);
+    }
+
+    /** Returns the original image's height */
+    public int getHeight() {
+        checkRecycled("getHeight called on recycled region decoder");
+        return nativeGetHeight(mNativeBitmapRegionDecoder);
+    }
+
+    /**
+     * Frees up the memory associated with this region decoder, and mark the
+     * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
+     * getWidth() or getHeight() is called.
+     *
+     * <p>This operation cannot be reversed, so it should only be called if you are
+     * sure there are no further uses for the region decoder. This is an advanced call,
+     * and normally need not be called, since the normal GC process will free up this
+     * memory when there are no more references to this region decoder.
+     */
+    public void recycle() {
+        if (!mRecycled) {
+            nativeClean(mNativeBitmapRegionDecoder);
+            mRecycled = true;
+        }
+    }
+
+    /**
+     * Returns true if this region decoder has been recycled.
+     * If so, then it is an error to try use its method.
+     *
+     * @return true if the region decoder has been recycled
+     */
+    public final boolean isRecycled() {
+        return mRecycled;
+    }
+
+    /**
+     * Called by methods that want to throw an exception if the region decoder
+     * has already been recycled.
+     */
+    private void checkRecycled(String errorMessage) {
+        if (mRecycled) {
+            throw new IllegalStateException(errorMessage);
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            recycle();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static native Bitmap nativeDecodeRegion(int lbm,
+            int start_x, int start_y, int width, int height,
+            BitmapFactory.Options options);
+    private static native int nativeGetWidth(int lbm);
+    private static native int nativeGetHeight(int lbm);
+    private static native void nativeClean(int lbm);
+
+    private static native BitmapRegionDecoder nativeNewInstance(
+            byte[] data, int offset, int length, boolean isShareable);
+    private static native BitmapRegionDecoder nativeNewInstance(
+            FileDescriptor fd, boolean isShareable);
+    private static native BitmapRegionDecoder nativeNewInstance(
+            InputStream is, byte[] storage, boolean isShareable);
+    private static native BitmapRegionDecoder nativeNewInstance(
+            int asset, boolean isShareable);
+}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index ed09f89..05b2d60 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -27,6 +27,7 @@
     int mSize;
     Element[] mElements;
     String[] mElementNames;
+    int[] mArraySizes;
 
     DataType mType;
     DataKind mKind;
@@ -313,11 +314,12 @@
         return rs.mElement_MATRIX_2X2;
     }
 
-    Element(int id, RenderScript rs, Element[] e, String[] n) {
+    Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
         super(id, rs);
         mSize = 0;
         mElements = e;
         mElementNames = n;
+        mArraySizes = as;
         for (int ct = 0; ct < mElements.length; ct++ ) {
             mSize += mElements[ct].mSize;
         }
@@ -441,6 +443,7 @@
         RenderScript mRS;
         Element[] mElements;
         String[] mElementNames;
+        int[] mArraySizes;
         int mCount;
 
         public Builder(RenderScript rs) {
@@ -448,35 +451,49 @@
             mCount = 0;
             mElements = new Element[8];
             mElementNames = new String[8];
+            mArraySizes = new int[8];
         }
 
-        public void add(Element element, String name) {
+        public void add(Element element, String name, int arraySize) {
+            if (arraySize < 1) {
+                throw new IllegalArgumentException("Array size cannot be less than 1.");
+            }
             if(mCount == mElements.length) {
                 Element[] e = new Element[mCount + 8];
                 String[] s = new String[mCount + 8];
+                int[] as = new int[mCount + 8];
                 System.arraycopy(mElements, 0, e, 0, mCount);
                 System.arraycopy(mElementNames, 0, s, 0, mCount);
+                System.arraycopy(mArraySizes, 0, as, 0, mCount);
                 mElements = e;
                 mElementNames = s;
+                mArraySizes = as;
             }
             mElements[mCount] = element;
             mElementNames[mCount] = name;
+            mArraySizes[mCount] = arraySize;
             mCount++;
         }
 
+        public void add(Element element, String name) {
+            add(element, name, 1);
+        }
+
         public Element create() {
             mRS.validate();
             Element[] ein = new Element[mCount];
             String[] sin = new String[mCount];
+            int[] asin = new int[mCount];
             java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
             java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
+            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
 
             int[] ids = new int[ein.length];
             for (int ct = 0; ct < ein.length; ct++ ) {
                 ids[ct] = ein[ct].mID;
             }
-            int id = mRS.nElementCreate2(ids, sin);
-            return new Element(id, mRS, ein, sin);
+            int id = mRS.nElementCreate2(ids, sin, asin);
+            return new Element(id, mRS, ein, sin, asin);
         }
     }
 
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 62d70a7..1f3e159 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -152,9 +152,9 @@
     synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
         return rsnElementCreate(mContext, type, kind, norm, vecSize);
     }
-    native int  rsnElementCreate2(int con, int[] elements, String[] names);
-    synchronized int nElementCreate2(int[] elements, String[] names) {
-        return rsnElementCreate2(mContext, elements, names);
+    native int  rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
+    synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+        return rsnElementCreate2(mContext, elements, names, arraySizes);
     }
     native void rsnElementGetNativeData(int con, int id, int[] elementData);
     synchronized void nElementGetNativeData(int id, int[] elementData) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index c8e6656..f07dbfd8 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -253,12 +253,13 @@
 }
 
 static jint
-nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names)
+nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes)
 {
     int fieldCount = _env->GetArrayLength(_ids);
     LOG_API("nElementCreate2, con(%p)", con);
 
     jint *ids = _env->GetIntArrayElements(_ids, NULL);
+    jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
     const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
     size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
 
@@ -267,12 +268,13 @@
         nameArray[ct] = _env->GetStringUTFChars(s, NULL);
         sizeArray[ct] = _env->GetStringUTFLength(s);
     }
-    jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray);
+    jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray, (const uint32_t *)arraySizes);
     for (int ct=0; ct < fieldCount; ct++) {
         jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
         _env->ReleaseStringUTFChars(s, nameArray[ct]);
     }
     _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
+    _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
     free(nameArray);
     free(sizeArray);
     return (jint)id;
@@ -1230,7 +1232,7 @@
 {"rsnFontCreateFromFile",            "(ILjava/lang/String;II)I",             (void*)nFontCreateFromFile },
 
 {"rsnElementCreate",                 "(IIIZI)I",                              (void*)nElementCreate },
-{"rsnElementCreate2",                "(I[I[Ljava/lang/String;)I",             (void*)nElementCreate2 },
+{"rsnElementCreate2",                "(I[I[Ljava/lang/String;[I)I",           (void*)nElementCreate2 },
 {"rsnElementGetNativeData",          "(II[I)V",                               (void*)nElementGetNativeData },
 {"rsnElementGetSubElements",         "(II[I[Ljava/lang/String;)V",           (void*)nElementGetSubElements },
 
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index c388ba8..fdceb84 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -69,7 +69,7 @@
     /* Destroys the consumer and releases its input channel. */
     ~AInputQueue();
 
-    void attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data);
+    void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
 
     void detachLooper();
 
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index 81230e8..bc616eb 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -111,12 +111,18 @@
      * This method can be called on any thread.
      * This method may block briefly if it needs to wake the poll loop.
      */
-    void setCallback(int fd, int events, Callback callback, void* data = NULL);
+    void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);
 
     /**
+     * Convenience for above setCallback when ident is not used.  In this case
+     * the ident is set to POLL_CALLBACK.
+     */
+    void setCallback(int fd, int events, Callback callback, void* data = NULL);
+    
+    /**
      * Like setCallback(), but for the NDK callback function.
      */
-    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+    void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
             void* data);
     
     /**
@@ -153,11 +159,13 @@
     struct RequestedCallback {
         Callback callback;
         ALooper_callbackFunc* looperCallback;
+        int ident;
         void* data;
     };
 
     struct PendingCallback {
         int fd;
+        int ident;
         int events;
         Callback callback;
         ALooper_callbackFunc* looperCallback;
@@ -185,7 +193,7 @@
     void openWakePipe();
     void closeWakePipe();
 
-    void setCallbackCommon(int fd, int events, Callback callback,
+    void setCallbackCommon(int fd, int ident, int events, Callback callback,
             ALooper_callbackFunc* looperCallback, void* data);
     ssize_t getRequestIndexLocked(int fd);
     void wakeAndLock();
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 3396f25..7eb6da5 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -86,7 +86,7 @@
     Mutex::Autolock _l(mLock);
     if (mPollLoop == 0) {
         mPollLoop = new PollLoop(true);
-        mPollLoop->setCallback(getFd(), POLLIN, NULL, NULL);
+        mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
     }
     return mPollLoop;
 }
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
index 2d7d32b..f48895c 100644
--- a/libs/rs/java/ModelViewer/res/raw/robot.a3d
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
index 9672a6a..85c1d42 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
@@ -105,7 +105,7 @@
         bs.setMin(Sampler.Value.LINEAR);
         bs.setMag(Sampler.Value.LINEAR);
         bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.WRAP);
+        bs.setWrapT(Sampler.Value.CLAMP);
         mSampler = bs.create();
 
         ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -123,7 +123,6 @@
 
         mPVA = new ProgramVertex.MatrixAllocation(mRS);
         mPVBackground.bindAllocation(mPVA);
-        mPVA.setupProjectionNormalized(mWidth, mHeight);
 
         mScript.set_gPVBackground(mPVBackground);
     }
@@ -159,14 +158,14 @@
         mGroup1.addChild(mRobot1);
         mGroup1.addChild(mRobot2);
 
-        mGroup1.setTransform(0, new Float4(0.0f, 0.0f, 5.0f, 0.0f), TransformType.TRANSLATE);
+        mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE);
         mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE);
 
-        mRobot1.setTransform(0, new Float4(-2.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
+        mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
         mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE);
         mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE);
 
-        mRobot2.setTransform(0, new Float4(2.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
+        mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
         mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE);
         mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE);
     }
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
index b8b0119..d8d1a6e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
@@ -79,7 +79,7 @@
             mRotation += 360;
         }
 
-        mScript.set_gRotate(-(float)mRotation);
+        mScript.set_gRotate((float)mRotation);
 
         mLastX = x;
         mLastY = y;
@@ -101,7 +101,7 @@
         bs.setMin(Sampler.Value.LINEAR);
         bs.setMag(Sampler.Value.LINEAR);
         bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.WRAP);
+        bs.setWrapT(Sampler.Value.CLAMP);
         mSampler = bs.create();
 
         ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -119,7 +119,6 @@
 
         mPVA = new ProgramVertex.MatrixAllocation(mRS);
         mPVBackground.bindAllocation(mPVA);
-        mPVA.setupProjectionNormalized(mWidth, mHeight);
 
         mScript.set_gPVBackground(mPVBackground);
     }
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index c794438..ce6bb1e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -71,6 +71,10 @@
     rsgClearDepth(1.0f);
 
     rsgBindProgramVertex(gPVBackground);
+    rs_matrix4x4 proj;
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
 
     rsgBindProgramFragment(gPFBackground);
     rsgBindProgramStore(gPFSBackground);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index adb609c..43be266 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -46,6 +46,10 @@
     rsgClearDepth(1.0f);
 
     rsgBindProgramVertex(gPVBackground);
+    rs_matrix4x4 proj;
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
 
     rsgBindProgramFragment(gPFBackground);
     rsgBindProgramStore(gPFSBackground);
@@ -54,9 +58,9 @@
     rs_matrix4x4 matrix;
     rsMatrixLoadIdentity(&matrix);
     // Position our model on the screen
-    rsMatrixTranslate(&matrix, 0.0f, -0.3f, 1.2f);
+    rsMatrixTranslate(&matrix, 0.0f, -0.3f, -10.0f);
     rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
-    rsMatrixRotate(&matrix, -25.0f, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&matrix, 25.0f, 1.0f, 0.0f, 0.0f);
     rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
     rsgProgramVertexLoadModelMatrix(&matrix);
 
diff --git a/libs/rs/java/Samples/res/raw/torus.a3d b/libs/rs/java/Samples/res/raw/torus.a3d
index d09bc13..0322b01 100644
--- a/libs/rs/java/Samples/res/raw/torus.a3d
+++ b/libs/rs/java/Samples/res/raw/torus.a3d
Binary files differ
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ad162bb..c7fb2af 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -80,6 +80,7 @@
 	param const RsElement * elements
 	param const char ** names
 	param const size_t * nameLengths
+	param const uint32_t * arraySize
 	ret RsElement
 	}
 
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 2602dd4..0b7bb27 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -65,7 +65,7 @@
 
     size_t total = 0;
     for (size_t ct=0; ct < mFieldCount; ct++) {
-        total += mFields[ct].e->mBits;
+        total += mFields[ct].e->mBits * mFields[ct].arraySize;;
     }
     return total;
 }
@@ -95,6 +95,7 @@
     stream->addU32(mFieldCount);
     for(uint32_t ct = 0; ct < mFieldCount; ct++) {
         stream->addString(&mFields[ct].name);
+        stream->addU32(mFields[ct].arraySize);
         mFields[ct].e->serialize(stream);
     }
 }
@@ -122,6 +123,7 @@
         elem->mFields = new ElementField_t [elem->mFieldCount];
         for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) {
             stream->loadString(&elem->mFields[ct].name);
+            elem->mFields[ct].arraySize = stream->loadU32();
             Element *fieldElem = Element::createFromStream(rsc, stream);
             elem->mFields[ct].e.set(fieldElem);
             elem->mFields[ct].offsetBits = offset;
@@ -155,7 +157,8 @@
             for (uint32_t i=0; i < elem->mFieldCount; i++) {
                 if ((ee->mFields[i].e.get() != elem->mFields[i].e.get()) ||
                     (ee->mFields[i].name.length() != elem->mFields[i].name.length()) ||
-                    (ee->mFields[i].name != elem->mFields[i].name)) {
+                    (ee->mFields[i].name != elem->mFields[i].name) ||
+                    (ee->mFields[i].arraySize != elem->mFields[i].arraySize)) {
                     match = false;
                     break;
                 }
@@ -200,7 +203,7 @@
 }
 
 const Element * Element::create(Context *rsc, size_t count, const Element **ein,
-                            const char **nin, const size_t * lengths)
+                            const char **nin, const size_t * lengths, const uint32_t *asin)
 {
     // Look for an existing match.
     for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
@@ -210,7 +213,8 @@
             for (uint32_t i=0; i < count; i++) {
                 if ((ee->mFields[i].e.get() != ein[i]) ||
                     (ee->mFields[i].name.length() != lengths[i]) ||
-                    (ee->mFields[i].name != nin[i])) {
+                    (ee->mFields[i].name != nin[i]) ||
+                    (ee->mFields[i].arraySize != asin[i])) {
                     match = false;
                     break;
                 }
@@ -230,6 +234,7 @@
         e->mFields[ct].e.set(ein[ct]);
         e->mFields[ct].name.setTo(nin[ct], lengths[ct]);
         e->mFields[ct].offsetBits = bits;
+        e->mFields[ct].arraySize = asin[ct];
         bits += ein[ct]->getSizeBits();
 
         if (ein[ct]->mHasReference) {
@@ -274,7 +279,11 @@
     const uint8_t *p = static_cast<const uint8_t *>(ptr);
     for (uint32_t i=0; i < mFieldCount; i++) {
         if (mFields[i].e->mHasReference) {
-            mFields[i].e->incRefs(&p[mFields[i].offsetBits >> 3]);
+            p = &p[mFields[i].offsetBits >> 3];
+            for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+                mFields[i].e->incRefs(p);
+                p += mFields[i].e->getSizeBytes();
+            }
         }
     }
 }
@@ -293,7 +302,11 @@
     const uint8_t *p = static_cast<const uint8_t *>(ptr);
     for (uint32_t i=0; i < mFieldCount; i++) {
         if (mFields[i].e->mHasReference) {
-            mFields[i].e->decRefs(&p[mFields[i].offsetBits >> 3]);
+            p = &p[mFields[i].offsetBits >> 3];
+            for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+                mFields[i].e->decRefs(p);
+                p += mFields[i].e->getSizeBytes();
+            }
         }
     }
 }
@@ -331,10 +344,11 @@
                              size_t count,
                              const RsElement * ein,
                              const char ** names,
-                             const size_t * nameLengths)
+                             const size_t * nameLengths,
+                             const uint32_t * arraySizes)
 {
     //LOGE("rsi_ElementCreate2 %i", count);
-    const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
+    const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes);
     e->incUserRef();
     return (RsElement)e;
 }
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index b5dad7a2..42eef4a 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -66,7 +66,7 @@
     static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
                             bool isNorm, uint32_t vecSize);
     static const Element * create(Context *rsc, size_t count, const Element **,
-                            const char **, const size_t * lengths);
+                            const char **, const size_t * lengths, const uint32_t *asin);
 
     void incRefs(const void *) const;
     void decRefs(const void *) const;
@@ -80,6 +80,7 @@
         String8 name;
         ObjectBaseRef<const Element> e;
         uint32_t offsetBits;
+        uint32_t arraySize;
     } ElementField_t;
     ElementField_t *mFields;
     size_t mFieldCount;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 7661d499..5889bfb 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -488,8 +488,9 @@
     size_t lengths[2];
     lengths[0] = posName.size();
     lengths[1] = texName.size();
+    uint32_t arraySizes[2] = {1, 1};
 
-    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
+    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
 
     Type *vertexDataType = new Type(mRSC);
     vertexDataType->setDimX(mMaxNumberOfQuads * 4);
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index a140e22..662791d 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -17,7 +17,7 @@
 #include "rsContext.h"
 #include "rsScriptC.h"
 #include "rsMatrix.h"
-#include "../../../external/llvm/libbcc/include/bcc/bcc.h"
+#include "../../compile/libbcc/include/bcc/bcc.h"
 #include "utils/Timers.h"
 
 #include <GLES/gl.h>
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index f740fa0..6d3eeee 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -95,6 +95,7 @@
     RequestedCallback requestedCallback;
     requestedCallback.callback = NULL;
     requestedCallback.looperCallback = NULL;
+    requestedCallback.ident = 0;
     requestedCallback.data = NULL;
     mRequestedCallbacks.insertAt(requestedCallback, 0);
 }
@@ -116,7 +117,7 @@
         mPendingFdsPos++;
         if (outEvents != NULL) *outEvents = pending.events;
         if (outData != NULL) *outData = pending.data;
-        return pending.fd;
+        return pending.ident;
     }
     
     mLock.lock();
@@ -182,6 +183,7 @@
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
             PendingCallback pending;
             pending.fd = requestedFd.fd;
+            pending.ident = requestedCallback.ident;
             pending.events = revents;
             pending.callback = requestedCallback.callback;
             pending.looperCallback = requestedCallback.looperCallback;
@@ -191,7 +193,7 @@
                 mPendingCallbacks.push(pending);
             } else if (pending.fd != mWakeReadPipeFd) {
                 if (result == POLL_CALLBACK) {
-                    result = pending.fd;
+                    result = pending.ident;
                     if (outEvents != NULL) *outEvents = pending.events;
                     if (outData != NULL) *outData = pending.data;
                 } else {
@@ -268,16 +270,20 @@
     return mAllowNonCallbacks;
 }
 
+void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
+    setCallbackCommon(fd, ident, events, callback, NULL, data);
+}
+
 void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
-    setCallbackCommon(fd, events, callback, NULL, data);
+    setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
 }
 
-void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
         void* data) {
-    setCallbackCommon(fd, events, NULL, callback, data);
+    setCallbackCommon(fd, ident, events, NULL, callback, data);
 }
 
-void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
+void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
         ALooper_callbackFunc* looperCallback, void* data) {
 
 #if DEBUG_CALLBACKS
@@ -305,6 +311,7 @@
     RequestedCallback requestedCallback;
     requestedCallback.callback = callback;
     requestedCallback.looperCallback = looperCallback;
+    requestedCallback.ident = ident;
     requestedCallback.data = data;
 
     ssize_t index = getRequestIndexLocked(fd);
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 2b1f490..e5ece8e 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 
 #include <cutils/sched_policy.h>
+#include <cutils/properties.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -57,7 +58,7 @@
 // ----------------------------------------------------------------------------
 
 /*
- * Create and run a new thead.
+ * Create and run a new thread.
  *
  * We create it "detached", so it cleans up after itself.
  */
@@ -280,6 +281,22 @@
 #endif
 }
 
+#if defined(HAVE_PTHREADS)
+static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
+static bool gDoSchedulingGroup = true;
+
+static void checkDoSchedulingGroup(void) {
+    char buf[PROPERTY_VALUE_MAX];
+    int len = property_get("debug.sys.noschedgroups", buf, "");
+    if (len > 0) {
+        int temp;
+        if (sscanf(buf, "%d", &temp) == 1) {
+            gDoSchedulingGroup = temp == 0;
+        }
+    }
+}
+#endif
+
 int androidSetThreadSchedulingGroup(pid_t tid, int grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
@@ -287,9 +304,12 @@
     }
 
 #if defined(HAVE_PTHREADS)
-    if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
-                                      SP_BACKGROUND : SP_FOREGROUND)) {
-        return PERMISSION_DENIED;
+    pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+    if (gDoSchedulingGroup) {
+        if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                                          SP_BACKGROUND : SP_FOREGROUND)) {
+            return PERMISSION_DENIED;
+        }
     }
 #endif
     
@@ -303,10 +323,13 @@
 #if defined(HAVE_PTHREADS)
     int lasterr = 0;
 
-    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        rc = set_sched_policy(tid, SP_BACKGROUND);
-    } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
-        rc = set_sched_policy(tid, SP_FOREGROUND);
+    pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+    if (gDoSchedulingGroup) {
+        if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+            rc = set_sched_policy(tid, SP_BACKGROUND);
+        } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+            rc = set_sched_policy(tid, SP_FOREGROUND);
+        }
     }
 
     if (rc) {
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index a0e01c6..2d53136 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -636,7 +636,7 @@
         memcpy(buffer, ptr, uncompLen);
     } else {
         if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
-            goto unmap;
+            goto bail;
     }
 
     if (compLen > kSequentialMin)
@@ -644,8 +644,6 @@
 
     result = true;
 
-unmap:
-    file->release();
 bail:
     return result;
 }
@@ -669,7 +667,7 @@
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
-    FileMap* file = createEntryFileMap(entry);
+    const FileMap* file = createEntryFileMap(entry);
     if (file == NULL) {
         goto bail;
     }
@@ -680,23 +678,21 @@
         ssize_t actual = write(fd, ptr, uncompLen);
         if (actual < 0) {
             LOGE("Write failed: %s\n", strerror(errno));
-            goto unmap;
+            goto bail;
         } else if ((size_t) actual != uncompLen) {
             LOGE("Partial write during uncompress (%zd of %zd)\n",
                 (size_t)actual, (size_t)uncompLen);
-            goto unmap;
+            goto bail;
         } else {
             LOGI("+++ successful write\n");
         }
     } else {
         if (!inflateBuffer(fd, ptr, uncompLen, compLen))
-            goto unmap;
+            goto bail;
     }
 
     result = true;
 
-unmap:
-    file->release();
 bail:
     return result;
 }
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 507fa5a..c204a94 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -106,7 +106,12 @@
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
     android_native_buffer_t *buf;
-    CHECK_EQ(0, mSurface->dequeueBuffer(mSurface.get(), &buf));
+    int err;
+    if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
+        LOGW("Surface::dequeueBuffer returned error %d", err);
+        return;
+    }
+
     CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
 
     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
@@ -186,7 +191,9 @@
 
     CHECK_EQ(0, mapper.unlock(buf->handle));
 
-    CHECK_EQ(0, mSurface->queueBuffer(mSurface.get(), buf));
+    if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
+        LOGW("Surface::queueBuffer returned error %d", err);
+    }
     buf = NULL;
 }
 
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 379960a..c79f913 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -246,8 +246,8 @@
 
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc* callback, void* data) {
-    queue->attachLooper(looper, callback, data);
+        int ident, ALooper_callbackFunc* callback, void* data) {
+    queue->attachLooper(looper, ident, callback, data);
 }
 
 void AInputQueue_detachLooper(AInputQueue* queue) {
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 1564c47..0aeed77 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -72,9 +72,9 @@
     static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
 }
 
-void ALooper_addFd(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
         ALooper_callbackFunc* callback, void* data) {
-    static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
+    static_cast<PollLoop*>(looper)->setLooperCallback(fd, ident, events, callback, data);
 }
 
 int32_t ALooper_removeFd(ALooper* looper, int fd) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index db534e0..cf7635d 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -60,12 +60,12 @@
 }
 
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, ALooper_callbackFunc* callback, void* data)
+        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data)
 {
     sp<SensorEventQueue> queue =
             static_cast<SensorManager*>(manager)->createEventQueue();
     if (queue != 0) {
-        ALooper_addFd(looper, queue->getFd(), POLLIN, callback, data);
+        ALooper_addFd(looper, queue->getFd(), ident, POLLIN, callback, data);
         queue->looper = looper;
         queue->incStrong(manager);
     }
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 418f609..5b62da4 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -623,10 +623,10 @@
 
 /*
  * Add this input queue to a looper for processing.  See
- * ALooper_addFd() for information on the callback and data params.
+ * ALooper_addFd() for information on the ident, callback, and data params.
  */
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc* callback, void* data);
+        int ident, ALooper_callbackFunc* callback, void* data);
 
 /*
  * Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 2917216..287bcd5 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -111,7 +111,7 @@
  *
  * Returns ALOPER_POLL_ERROR if an error occurred.
  *
- * Returns a value >= 0 containing a file descriptor if it has data
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
  * and it has no callback function (requiring the caller here to handle it).
  * In this (and only this) case outEvents and outData will contain the poll
  * events and data associated with the fd.
@@ -145,10 +145,12 @@
  * descriptor was previously added, it is replaced.
  *
  * "fd" is the file descriptor to be added.
+ * "ident" is an identifier for this event, which is returned from
+ * ALooper_pollOnce().  Must be >= 0, or ALOOPER_POLL_CALLBACK if
+ * providing a non-NULL callback.
  * "events" are the poll events to wake up on.  Typically this is POLLIN.
  * "callback" is the function to call when there is an event on the file
  * descriptor.
- * "id" is an identifier to associated with this file descriptor, or 0.
  * "data" is a private data pointer to supply to the callback.
  *
  * There are two main uses of this function:
@@ -156,13 +158,13 @@
  * (1) If "callback" is non-NULL, then
  * this function will be called when there is data on the file descriptor.  It
  * should execute any events it has pending, appropriately reading from the
- * file descriptor.
+ * file descriptor.  The 'ident' is ignored in this case.
  *
- * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
- * when it has data available, requiring the caller to take care of processing
- * it.
+ * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+ * when its file descriptor has data available, requiring the caller to take
+ * care of processing it.
  */
-void ALooper_addFd(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
         ALooper_callbackFunc* callback, void* data);
 
 /**
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index b4ce024..a102d43 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -166,7 +166,7 @@
  * Creates a new sensor event queue and associate it with a looper.
  */
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, ALooper_callbackFunc* callback, void* data);
+        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
 
 /*
  * Destroys the event queue and free all resources associated to it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index 33acecb..48243ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -39,6 +39,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.Log;
 import android.view.Display;
@@ -468,7 +469,11 @@
         }
 
         // Restart the ticker if it's still running
-        tick(notification);
+        if (notification.notification.tickerText != null
+                && !TextUtils.equals(notification.notification.tickerText,
+                    oldEntry.notification.notification.tickerText)) {
+            tick(notification);
+        }
 
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index e742887..5f26af4 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -175,8 +175,7 @@
     }
 
     public int getPhoneType() {
-        // FIXME: add SIP phone type
-        return Phone.PHONE_TYPE_GSM;
+        return Phone.PHONE_TYPE_SIP;
     }
 
     public SignalStrength getSignalStrength() {
diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
index 64d11c5..2811b0d 100644
--- a/test-runner/src/android/test/ProviderTestCase2.java
+++ b/test-runner/src/android/test/ProviderTestCase2.java
@@ -74,7 +74,7 @@
     private IsolatedContext mProviderContext;
     private MockContentResolver mResolver;
 
-       private class MockContext2 extends MockContext {
+    private class MockContext2 extends MockContext {
 
         @Override
         public Resources getResources() {
@@ -87,6 +87,11 @@
             // one created through the regular Context
             return getContext().getDir("mockcontext2_" + name, mode);
         }
+
+        @Override
+        public Context getApplicationContext() {
+            return this;
+        }
     }
     /**
      * Constructor.
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 34cbc44..db1e5ef 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,16 @@
         </activity>
         
         <activity
+                android:name="ResizeActivity"
+                android:label="_Resize"
+                android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
                 android:name="TextGammaActivity"
                 android:label="_Gamma"
                 android:theme="@android:style/Theme.Translucent.NoTitleBar">
diff --git a/tests/HwAccelerationTest/res/layout/form.xml b/tests/HwAccelerationTest/res/layout/form.xml
new file mode 100644
index 0000000..0b17db1
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/form.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="First name" />
+        
+        <EditText
+            android:layout_width="0dip"
+            android:layout_weight="1.0"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="3dip"
+            android:hint="Enter your first name" />
+        
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Last name" />
+        
+        <EditText
+            android:layout_width="0dip"
+            android:layout_weight="1.0"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="3dip"
+            android:hint="Enter your last name" />
+        
+    </LinearLayout>
+    
+    <EditText
+        android:layout_width="match_parent"
+        android:layout_weight="1.0"
+        android:layout_height="0dip"
+        android:background="#ff7f0000" />
+    
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java
new file mode 100644
index 0000000..e5771b8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ResizeActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(R.layout.form);
+    }
+}