Merge "Rename ApplicationContext to ContextImpl."
diff --git a/api/current.xml b/api/current.xml
index 0c46100..0893e4e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -55606,7 +55606,7 @@
 >
 </field>
 </class>
-<class name="GestureUtilities"
+<class name="GestureUtils"
  extends="java.lang.Object"
  abstract="false"
  static="false"
@@ -86774,7 +86774,7 @@
  visibility="public"
 >
 </method>
-<method name="getMobileRxPkts"
+<method name="getMobileRxPackets"
  return="long"
  abstract="false"
  native="false"
@@ -86796,7 +86796,7 @@
  visibility="public"
 >
 </method>
-<method name="getMobileTxPkts"
+<method name="getMobileTxPackets"
  return="long"
  abstract="false"
  native="false"
@@ -86818,7 +86818,7 @@
  visibility="public"
 >
 </method>
-<method name="getTotalRxPkts"
+<method name="getTotalRxPackets"
  return="long"
  abstract="false"
  native="false"
@@ -86840,7 +86840,7 @@
  visibility="public"
 >
 </method>
-<method name="getTotalTxPkts"
+<method name="getTotalTxPackets"
  return="long"
  abstract="false"
  native="false"
@@ -159353,6 +159353,21 @@
 </parameter>
 </method>
 <method name="tokenize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="out" type="java.util.Collection&lt;android.text.util.Rfc822Token&gt;">
+</parameter>
+</method>
+<method name="tokenize"
  return="android.text.util.Rfc822Token[]"
  abstract="false"
  native="false"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 8c15d0b..acfbb07 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -315,7 +315,7 @@
                 for (RestoreSet s : sets) {
                     if (s.token == token) {
                         System.out.println("Scheduling restore: " + s.name);
-                        didRestore = (mRestore.performRestore(token, observer) == 0);
+                        didRestore = (mRestore.restoreAll(token, observer) == 0);
                         break;
                     }
                 }
diff --git a/common/java/com/android/common/Base64.java b/common/java/com/android/common/Base64.java
new file mode 100644
index 0000000..d108f44
--- /dev/null
+++ b/common/java/com/android/common/Base64.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+/**
+ * Utilities for encoding and decoding the Base64 encoding.  See RFCs
+ * 2045 and 3548.
+ */
+public class Base64 {
+    /**
+     * Encoder flag bit to indicate you want the padding '='
+     * characters at the end (if any) to be omitted.
+     */
+    public static final int NO_PADDING = 1;
+
+    /**
+     * Encoder flag bit to indicate you want all line terminators to
+     * be omitted (ie, the output will be on one long line).
+     */
+    public static final int NO_WRAP = 2;
+
+    /**
+     * Encoder flag bit to indicate you want lines to be ended with
+     * CRLF instead of just LF.
+     */
+    public static final int CRLF = 4;
+
+    /**
+     * Encoder/decoder flag bit to indicate using the "web safe"
+     * variant of Base64 (see RFC 3548 section 4) where '-' and '_'
+     * are used in place of '+' and '/'.
+     */
+    public static final int WEB_SAFE = 8;
+
+    /**
+     * Lookup table for turning bytes into their position in the
+     * Base64 alphabet.
+     */
+    private static final int DECODE[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    };
+
+    /**
+     * Decode lookup table for the "web safe" variant (RFC 3548
+     * sec. 4) where - and _ replace + and /.
+     */
+    private static final int DECODE_WEBSAFE[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    };
+
+    /** Non-data values in the DECODE arrays. */
+    private static final int SKIP = -1;
+    private static final int EQUALS = -2;
+
+    /**
+     * Decode the Base64-encoded data in input and return the data in
+     * a new byte array.
+     *
+     * The padding '=' characters at the end are considered optional, but
+     * if any are present, there must be the correct number of them.
+     *
+     * @param input the input String to decode, which is converted to
+     *               bytes using the default charset
+     * @param flags  controls certain features of the decoded output.
+     *               Passing 0 to decode standard Base64.
+     *
+     * @throws IllegalArgumentException if the input contains
+     * incorrect padding
+     */
+    public static byte[] decode(String str, int flags) {
+        return decode(str.getBytes(), flags);
+    }
+
+    /**
+     * Decode the Base64-encoded data in input and return the data in
+     * a new byte array.
+     *
+     * The padding '=' characters at the end are considered optional, but
+     * if any are present, there must be the correct number of them.
+     *
+     * @param input the input array to decode
+     * @param flags  controls certain features of the decoded output.
+     *               Passing 0 to decode standard Base64.
+     *
+     * @throws IllegalArgumentException if the input contains
+     * incorrect padding
+     */
+    public static byte[] decode(byte[] input, int flags) {
+        return decode(input, 0, input.length, flags);
+    }
+
+    /**
+     * Decode the Base64-encoded data in input and return the data in
+     * a new byte array.
+     *
+     * The padding '=' characters at the end are considered optional, but
+     * if any are present, there must be the correct number of them.
+     *
+     * @param input  the data to decode
+     * @param offset the position within the input array at which to start
+     * @param len    the number of bytes of input to decode
+     * @param flags  controls certain features of the decoded output.
+     *               Passing 0 to decode standard Base64.
+     *
+     * @throws IllegalArgumentException if the input contains
+     * incorrect padding
+     */
+    public static byte[] decode(byte[] input, int offset, int len, int flags) {
+        int p = offset;
+        // Allocate space for the most data the input could represent.
+        // (It could contain less if it contains whitespace, etc.)
+        byte[] output = new byte[len*3/4];
+        len += offset;
+        int op = 0;
+
+        final int[] decode = ((flags & WEB_SAFE) == 0) ?
+            DECODE : DECODE_WEBSAFE;
+
+        int state = 0;
+        int value = 0;
+
+        while (p < len) {
+
+            // Try the fast path:  we're starting a new tuple and the
+            // next four bytes of the input stream are all data
+            // bytes.  This corresponds to going through states
+            // 0-1-2-3-0.  We expect to use this method for most of
+            // the data.
+            //
+            // If any of the next four bytes of input are non-data
+            // (whitespace, etc.), value will end up negative.  (All
+            // the non-data values in decode are small negative
+            // numbers, so shifting any of them up and or'ing them
+            // together will result in a value with its top bit set.)
+            //
+            // You can remove this whole block and the output should
+            // be the same, just slower.
+            if (state == 0 && p+4 <= len &&
+                (value = ((decode[input[p] & 0xff] << 18) |
+                          (decode[input[p+1] & 0xff] << 12) |
+                          (decode[input[p+2] & 0xff] << 6) |
+                          (decode[input[p+3] & 0xff]))) >= 0) {
+                output[op+2] = (byte) value;
+                output[op+1] = (byte) (value >> 8);
+                output[op] = (byte) (value >> 16);
+                op += 3;
+                p += 4;
+                continue;
+            }
+
+            // The fast path isn't available -- either we've read a
+            // partial tuple, or the next four input bytes aren't all
+            // data, or whatever.  Fall back to the slower state
+            // machine implementation.
+            //
+            // States 0-3 are reading through the next input tuple.
+            // State 4 is having read one '=' and expecting exactly
+            // one more.
+            // State 5 is expecting no more data or padding characters
+            // in the input.
+
+            int d = decode[input[p++] & 0xff];
+
+            switch (state) {
+                case 0:
+                    if (d >= 0) {
+                        value = d;
+                        ++state;
+                    } else if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+
+                case 1:
+                    if (d >= 0) {
+                        value = (value << 6) | d;
+                        ++state;
+                    } else if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+
+                case 2:
+                    if (d >= 0) {
+                        value = (value << 6) | d;
+                        ++state;
+                    } else if (d == EQUALS) {
+                        // Emit the last (partial) output tuple;
+                        // expect exactly one more padding character.
+                        output[op++] = (byte) (value >> 4);
+                        state = 4;
+                    } else if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+
+                case 3:
+                    if (d >= 0) {
+                        // Emit the output triple and return to state 0.
+                        value = (value << 6) | d;
+                        output[op+2] = (byte) value;
+                        output[op+1] = (byte) (value >> 8);
+                        output[op] = (byte) (value >> 16);
+                        op += 3;
+                        state = 0;
+                    } else if (d == EQUALS) {
+                        // Emit the last (partial) output tuple;
+                        // expect no further data or padding characters.
+                        output[op+1] = (byte) (value >> 2);
+                        output[op] = (byte) (value >> 10);
+                        op += 2;
+                        state = 5;
+                    } else if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+
+                case 4:
+                    if (d == EQUALS) {
+                        ++state;
+                    } else if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+
+                case 5:
+                    if (d != SKIP) {
+                        throw new IllegalArgumentException("bad base-64");
+                    }
+                    break;
+            }
+        }
+
+        // Done reading input.  Now figure out where we are left in
+        // the state machine and finish up.
+
+        switch (state) {
+            case 0:
+                // Output length is a multiple of three.  Fine.
+                break;
+            case 1:
+                // Read one extra input byte, which isn't enough to
+                // make another output byte.  Illegal.
+                throw new IllegalArgumentException("bad base-64");
+            case 2:
+                // Read two extra input bytes, enough to emit 1 more
+                // output byte.  Fine.
+                output[op++] = (byte) (value >> 4);
+                break;
+            case 3:
+                // Read three extra input bytes, enough to emit 2 more
+                // output bytes.  Fine.
+                output[op+1] = (byte) (value >> 2);
+                output[op] = (byte) (value >> 10);
+                op += 2;
+                break;
+            case 4:
+                // Read one padding '=' when we expected 2.  Illegal.
+                throw new IllegalArgumentException("bad base-64");
+            case 5:
+                // Read all the padding '='s we expected and no more.
+                // Fine.
+                break;
+        }
+
+        // Maybe we got lucky and allocated exactly enough output space.
+        if (op == output.length) {
+            return output;
+        }
+
+        // Need to shorten the array, so allocate a new one of the
+        // right size and copy.
+        byte[] temp = new byte[op];
+        System.arraycopy(output, 0, temp, 0, op);
+        return temp;
+    }
+
+    /**
+     * Emit a new line every this many output tuples.  Corresponds to
+     * a 76-character line length (the maximum allowable according to
+     * RFC 2045).
+     */
+    private static final int LINE_GROUPS = 19;
+
+    /**
+     * Lookup table for turning Base64 alphabet positions (6 bits)
+     * into output bytes.
+     */
+    private static final byte ENCODE[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+        'w', 'x', 'y', 'z', '0', '1', '2', '3',
+        '4', '5', '6', '7', '8', '9', '+', '/',
+    };
+
+    /**
+     * Lookup table for turning Base64 alphabet positions (6 bits)
+     * into output bytes.
+     */
+    private static final byte ENCODE_WEBSAFE[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+        'w', 'x', 'y', 'z', '0', '1', '2', '3',
+        '4', '5', '6', '7', '8', '9', '-', '_',
+    };
+
+    /**
+     * Base64-encode the given data and return a newly allocated
+     * String with the result.
+     *
+     * @param input  the data to encode
+     * @param flags  controls certain features of the encoded output.
+     *               Passing 0 results in output that adheres to RFC
+     *               2045.
+     */
+    public static String encodeString(byte[] input, int flags) {
+        return new String(encode(input, flags));
+    }
+
+    /**
+     * Base64-encode the given data and return a newly allocated
+     * String with the result.
+     *
+     * @param input  the data to encode
+     * @param offset the position within the input array at which to
+     *               start
+     * @param len    the number of bytes of input to encode
+     * @param flags  controls certain features of the encoded output.
+     *               Passing 0 results in output that adheres to RFC
+     *               2045.
+     */
+    public static String encodeString(byte[] input, int offset, int len, int flags) {
+        return new String(encode(input, offset, len, flags));
+    }
+
+    /**
+     * Base64-encode the given data and return a newly allocated
+     * byte[] with the result.
+     *
+     * @param input  the data to encode
+     * @param flags  controls certain features of the encoded output.
+     *               Passing 0 results in output that adheres to RFC
+     *               2045.
+     */
+    public static byte[] encode(byte[] input, int flags) {
+        return encode(input, 0, input.length, flags);
+    }
+
+    /**
+     * Base64-encode the given data and return a newly allocated
+     * byte[] with the result.
+     *
+     * @param input  the data to encode
+     * @param offset the position within the input array at which to
+     *               start
+     * @param len    the number of bytes of input to encode
+     * @param flags  controls certain features of the encoded output.
+     *               Passing 0 results in output that adheres to RFC
+     *               2045.
+     */
+    public static byte[] encode(byte[] input, int offset, int len, int flags) {
+        final boolean do_padding = (flags & NO_PADDING) == 0;
+        final boolean do_newline = (flags & NO_WRAP) == 0;
+        final boolean do_cr = (flags & CRLF) != 0;
+
+        final byte[] encode = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+
+        // Compute the exact length of the array we will produce.
+        int output_len = len / 3 * 4;
+
+        // Account for the tail of the data and the padding bytes, if any.
+        if (do_padding) {
+            if (len % 3 > 0) {
+                output_len += 4;
+            }
+        } else {
+            switch (len % 3) {
+                case 0: break;
+                case 1: output_len += 2; break;
+                case 2: output_len += 3; break;
+            }
+        }
+
+        // Account for the newlines, if any.
+        if (do_newline && len > 0) {
+            output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (do_cr ? 2 : 1);
+        }
+
+        int op = 0;
+        byte[] output = new byte[output_len];
+
+        // The main loop, turning 3 input bytes into 4 output bytes on
+        // each iteration.
+        int count = do_newline ? LINE_GROUPS : -1;
+        int p = offset;
+        len += offset;
+        while (p+3 <= len) {
+            int v = ((input[p++] & 0xff) << 16) |
+                ((input[p++] & 0xff) << 8) |
+                (input[p++] & 0xff);
+            output[op++] = encode[(v >> 18) & 0x3f];
+            output[op++] = encode[(v >> 12) & 0x3f];
+            output[op++] = encode[(v >> 6) & 0x3f];
+            output[op++] = encode[v & 0x3f];
+            if (--count == 0) {
+                if (do_cr) output[op++] = '\r';
+                output[op++] = '\n';
+                count = LINE_GROUPS;
+            }
+        }
+
+        // Finish up the tail of the input.
+        if (p == len-1) {
+            int v = (input[p] & 0xff) << 4;
+            output[op++] = encode[(v >> 6) & 0x3f];
+            output[op++] = encode[v & 0x3f];
+            if (do_padding) {
+                output[op++] = '=';
+                output[op++] = '=';
+            }
+            if (do_newline) {
+                if (do_cr) output[op++] = '\r';
+                output[op++] = '\n';
+            }
+        } else if (p == len-2) {
+            int v = ((input[p] & 0xff) << 10) | ((input[p+1] & 0xff) << 2);
+            output[op++] = encode[(v >> 12) & 0x3f];
+            output[op++] = encode[(v >> 6) & 0x3f];
+            output[op++] = encode[v & 0x3f];
+            if (do_padding) {
+                output[op++] = '=';
+            }
+            if (do_newline) {
+                if (do_cr) output[op++] = '\r';
+                output[op++] = '\n';
+            }
+        } else if (do_newline && op > 0 && count != LINE_GROUPS) {
+            if (do_cr) output[op++] = '\r';
+            output[op++] = '\n';
+        }
+
+        assert op == output.length;
+        return output;
+    }
+}
diff --git a/common/tests/src/com/android/common/Base64Test.java b/common/tests/src/com/android/common/Base64Test.java
new file mode 100644
index 0000000..39c4b20
--- /dev/null
+++ b/common/tests/src/com/android/common/Base64Test.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import junit.framework.TestCase;
+
+public class Base64Test extends TestCase {
+    private static final String TAG = "B64Test";
+
+    /** Decodes a string, returning a string. */
+    private String decodeString(String in) throws Exception {
+        byte[] out = Base64.decode(in, 0);
+        return new String(out);
+    }
+
+    /**
+     * Encodes the string 'in' using 'flags'.  Asserts that decoding
+     * gives the same string.  Returns the encoded string.
+     */
+    private String encodeString(String in, int flags) throws Exception {
+        String b64 = Base64.encodeString(in.getBytes(), flags);
+        String dec = decodeString(b64);
+        assertEquals(in, dec);
+        return b64;
+    }
+
+    /** Assert that decoding 'in' throws IllegalArgumentException. */
+    private void assertBad(String in) throws Exception {
+        try {
+            byte[] out = Base64.decode(in, 0);
+            fail("should have failed to decode");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    /** Assert that actual equals the first len bytes of expected. */
+    private void assertEquals(byte[] expected, int len, byte[] actual) {
+        assertEquals(len, actual.length);
+        for (int i = 0; i < len; ++i) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
+    public void testDecodeExtraChars() throws Exception {
+        // padding 0
+        assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
+        assertBad("aGVsbG8sIHdvcmxk=");
+        assertBad("aGVsbG8sIHdvcmxk==");
+        assertBad("aGVsbG8sIHdvcmxk =");
+        assertBad("aGVsbG8sIHdvcmxk = = ");
+        assertEquals("hello, world", decodeString(" aGVs bG8s IHdv cmxk  "));
+        assertEquals("hello, world", decodeString(" aGV sbG8 sIHd vcmx k "));
+        assertEquals("hello, world", decodeString(" aG VsbG 8sIH dvcm xk "));
+        assertEquals("hello, world", decodeString(" a GVsb G8sI Hdvc mxk "));
+        assertEquals("hello, world", decodeString(" a G V s b G 8 s I H d v c m x k "));
+        assertEquals("hello, world", decodeString("_a*G_V*s_b*G_8*s_I*H_d*v_c*m_x*k_"));
+        assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
+
+        // padding 1
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE="));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE"));
+        assertBad("aGVsbG8sIHdvcmxkPyE==");
+        assertBad("aGVsbG8sIHdvcmxkPyE ==");
+        assertBad("aGVsbG8sIHdvcmxkPyE = = ");
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E="));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E"));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ="));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E "));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E = "));
+        assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E   "));
+
+        // padding 2
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg=="));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg"));
+        assertBad("aGVsbG8sIHdvcmxkLg=");
+        assertBad("aGVsbG8sIHdvcmxkLg =");
+        assertBad("aGVsbG8sIHdvcmxkLg = ");
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g=="));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g"));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g =="));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g "));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g = = "));
+        assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g   "));
+    }
+
+    private static final byte[] BYTES = { (byte) 0xff, (byte) 0xee, (byte) 0xdd,
+                                          (byte) 0xcc, (byte) 0xbb, (byte) 0xaa,
+                                          (byte) 0x99, (byte) 0x88, (byte) 0x77 };
+
+    public void testBinaryDecode() throws Exception {
+        assertEquals(BYTES, 0, Base64.decode("", 0));
+        assertEquals(BYTES, 1, Base64.decode("/w==", 0));
+        assertEquals(BYTES, 2, Base64.decode("/+4=", 0));
+        assertEquals(BYTES, 3, Base64.decode("/+7d", 0));
+        assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
+        assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
+        assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
+        assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
+        assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
+    }
+
+    public void testWebSafe() throws Exception {
+        assertEquals(BYTES, 0, Base64.decode("", Base64.WEB_SAFE));
+        assertEquals(BYTES, 1, Base64.decode("_w==", Base64.WEB_SAFE));
+        assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.WEB_SAFE));
+        assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.WEB_SAFE));
+        assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.WEB_SAFE));
+        assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.WEB_SAFE));
+        assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.WEB_SAFE));
+        assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.WEB_SAFE));
+        assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.WEB_SAFE));
+
+        assertEquals("", Base64.encodeString(BYTES, 0, 0, Base64.WEB_SAFE));
+        assertEquals("_w==\n", Base64.encodeString(BYTES, 0, 1, Base64.WEB_SAFE));
+        assertEquals("_-4=\n", Base64.encodeString(BYTES, 0, 2, Base64.WEB_SAFE));
+        assertEquals("_-7d\n", Base64.encodeString(BYTES, 0, 3, Base64.WEB_SAFE));
+        assertEquals("_-7dzA==\n", Base64.encodeString(BYTES, 0, 4, Base64.WEB_SAFE));
+        assertEquals("_-7dzLs=\n", Base64.encodeString(BYTES, 0, 5, Base64.WEB_SAFE));
+        assertEquals("_-7dzLuq\n", Base64.encodeString(BYTES, 0, 6, Base64.WEB_SAFE));
+        assertEquals("_-7dzLuqmQ==\n", Base64.encodeString(BYTES, 0, 7, Base64.WEB_SAFE));
+        assertEquals("_-7dzLuqmYg=\n", Base64.encodeString(BYTES, 0, 8, Base64.WEB_SAFE));
+    }
+
+    public void testFlags() throws Exception {
+        assertEquals("YQ==\n",       encodeString("a", 0));
+        assertEquals("YQ==",         encodeString("a", Base64.NO_WRAP));
+        assertEquals("YQ\n",         encodeString("a", Base64.NO_PADDING));
+        assertEquals("YQ",           encodeString("a", Base64.NO_PADDING | Base64.NO_WRAP));
+        assertEquals("YQ==\r\n",     encodeString("a", Base64.CRLF));
+        assertEquals("YQ\r\n",       encodeString("a", Base64.CRLF | Base64.NO_PADDING));
+
+        assertEquals("YWI=\n",       encodeString("ab", 0));
+        assertEquals("YWI=",         encodeString("ab", Base64.NO_WRAP));
+        assertEquals("YWI\n",        encodeString("ab", Base64.NO_PADDING));
+        assertEquals("YWI",          encodeString("ab", Base64.NO_PADDING | Base64.NO_WRAP));
+        assertEquals("YWI=\r\n",     encodeString("ab", Base64.CRLF));
+        assertEquals("YWI\r\n",      encodeString("ab", Base64.CRLF | Base64.NO_PADDING));
+
+        assertEquals("YWJj\n",       encodeString("abc", 0));
+        assertEquals("YWJj",         encodeString("abc", Base64.NO_WRAP));
+        assertEquals("YWJj\n",       encodeString("abc", Base64.NO_PADDING));
+        assertEquals("YWJj",         encodeString("abc", Base64.NO_PADDING | Base64.NO_WRAP));
+        assertEquals("YWJj\r\n",     encodeString("abc", Base64.CRLF));
+        assertEquals("YWJj\r\n",     encodeString("abc", Base64.CRLF | Base64.NO_PADDING));
+
+        assertEquals("YWJjZA==\n",   encodeString("abcd", 0));
+        assertEquals("YWJjZA==",     encodeString("abcd", Base64.NO_WRAP));
+        assertEquals("YWJjZA\n",     encodeString("abcd", Base64.NO_PADDING));
+        assertEquals("YWJjZA",       encodeString("abcd", Base64.NO_PADDING | Base64.NO_WRAP));
+        assertEquals("YWJjZA==\r\n", encodeString("abcd", Base64.CRLF));
+        assertEquals("YWJjZA\r\n",   encodeString("abcd", Base64.CRLF | Base64.NO_PADDING));
+    }
+
+    public void testLineLength() throws Exception {
+        String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd";
+        String in_57 = in_56 + "e";
+        String in_58 = in_56 + "ef";
+        String in_59 = in_56 + "efg";
+        String in_60 = in_56 + "efgh";
+        String in_61 = in_56 + "efghi";
+
+        String prefix = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5emFi";
+        String out_56 = prefix + "Y2Q=\n";
+        String out_57 = prefix + "Y2Rl\n";
+        String out_58 = prefix + "Y2Rl\nZg==\n";
+        String out_59 = prefix + "Y2Rl\nZmc=\n";
+        String out_60 = prefix + "Y2Rl\nZmdo\n";
+        String out_61 = prefix + "Y2Rl\nZmdoaQ==\n";
+
+        // no newline for an empty input array.
+        assertEquals("", encodeString("", 0));
+
+        assertEquals(out_56, encodeString(in_56, 0));
+        assertEquals(out_57, encodeString(in_57, 0));
+        assertEquals(out_58, encodeString(in_58, 0));
+        assertEquals(out_59, encodeString(in_59, 0));
+        assertEquals(out_60, encodeString(in_60, 0));
+        assertEquals(out_61, encodeString(in_61, 0));
+
+        assertEquals(out_56.replaceAll("=", ""), encodeString(in_56, Base64.NO_PADDING));
+        assertEquals(out_57.replaceAll("=", ""), encodeString(in_57, Base64.NO_PADDING));
+        assertEquals(out_58.replaceAll("=", ""), encodeString(in_58, Base64.NO_PADDING));
+        assertEquals(out_59.replaceAll("=", ""), encodeString(in_59, Base64.NO_PADDING));
+        assertEquals(out_60.replaceAll("=", ""), encodeString(in_60, Base64.NO_PADDING));
+        assertEquals(out_61.replaceAll("=", ""), encodeString(in_61, Base64.NO_PADDING));
+
+        assertEquals(out_56.replaceAll("\n", ""), encodeString(in_56, Base64.NO_WRAP));
+        assertEquals(out_57.replaceAll("\n", ""), encodeString(in_57, Base64.NO_WRAP));
+        assertEquals(out_58.replaceAll("\n", ""), encodeString(in_58, Base64.NO_WRAP));
+        assertEquals(out_59.replaceAll("\n", ""), encodeString(in_59, Base64.NO_WRAP));
+        assertEquals(out_60.replaceAll("\n", ""), encodeString(in_60, Base64.NO_WRAP));
+        assertEquals(out_61.replaceAll("\n", ""), encodeString(in_61, Base64.NO_WRAP));
+    }
+}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 51d7393..72ec616 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -31,12 +31,12 @@
 public class StatusBarManager {
     /**
      * Flag for {@link #disable} to make the status bar not expandable.  Unless you also
-     * set {@link #DISABLE_NOTIFICATIONS}, new notifications will continue to show.
+     * set {@link #DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show.
      */
     public static final int DISABLE_EXPAND = 0x00000001;
 
     /**
-     * Flag for {@link #disable} to hide notification icons and ticker text.
+     * Flag for {@link #disable} to hide notification icons and scrolling ticker text.
      */
     public static final int DISABLE_NOTIFICATION_ICONS = 0x00000002;
 
@@ -47,6 +47,12 @@
     public static final int DISABLE_NOTIFICATION_ALERTS = 0x00000004;
 
     /**
+     * Flag for {@link #disable} to hide only the scrolling ticker.  Note that
+     * {@link #DISABLE_NOTIFICATION_ICONS} implies {@link #DISABLE_NOTIFICATION_TICKER}.
+     */
+    public static final int DISABLE_NOTIFICATION_TICKER = 0x00000008;
+
+    /**
      * Re-enable all of the status bar features that you've disabled.
      */
     public static final int DISABLE_NONE = 0x00000000;
diff --git a/core/java/android/backup/IRestoreSession.aidl b/core/java/android/backup/IRestoreSession.aidl
index fd40d98..bead395 100644
--- a/core/java/android/backup/IRestoreSession.aidl
+++ b/core/java/android/backup/IRestoreSession.aidl
@@ -40,6 +40,8 @@
      * Restore the given set onto the device, replacing the current data of any app
      * contained in the restore set with the data previously backed up.
      *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
      * @return Zero on success; nonzero on error.  The observer will only receive
      *   progress callbacks if this method returned zero.
      * @param token The token from {@link getAvailableRestoreSets()} corresponding to
@@ -47,7 +49,24 @@
      * @param observer If non-null, this binder points to an object that will receive
      *   progress callbacks during the restore operation.
      */
-    int performRestore(long token, IRestoreObserver observer);
+    int restoreAll(long token, IRestoreObserver observer);
+
+    /**
+     * Restore a single application from backup.  The data will be restored from the
+     * current backup dataset if the given package has stored data there, or from
+     * the dataset used during the last full device setup operation if the current
+     * backup dataset has no matching data.  If no backup data exists for this package
+     * in either source, a nonzero value will be returned.
+     *
+     * @return Zero on success; nonzero on error.  The observer will only receive
+     *   progress callbacks if this method returned zero.
+     * @param packageName The name of the package whose data to restore.  If this is
+     *   not the name of the caller's own package, then the android.permission.BACKUP
+     *   permission must be held.
+     * @param observer If non-null, this binder points to an object that will receive
+     *   progress callbacks during the restore operation.
+     */
+    int restorePackage(in String packageName, IRestoreObserver observer);
 
     /**
      * End this restore session.  After this method is called, the IRestoreSession binder
diff --git a/core/java/android/backup/RestoreSession.java b/core/java/android/backup/RestoreSession.java
index 6b35fe8..d10831e 100644
--- a/core/java/android/backup/RestoreSession.java
+++ b/core/java/android/backup/RestoreSession.java
@@ -58,25 +58,56 @@
      * Restore the given set onto the device, replacing the current data of any app
      * contained in the restore set with the data previously backed up.
      *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
      * @return Zero on success; nonzero on error.  The observer will only receive
      *   progress callbacks if this method returned zero.
-     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
+     * @param token The token from {@link getAvailableRestoreSets()} corresponding to
      *   the restore set that should be used.
-     * @param observer If non-null, this argument points to an object that will receive
-     *   progress callbacks during the restore operation. These callbacks will occur
-     *   on the main thread of the application.
+     * @param observer If non-null, this binder points to an object that will receive
+     *   progress callbacks during the restore operation.
      */
-    public int performRestore(long token, RestoreObserver observer) {
+    public int restoreAll(long token, RestoreObserver observer) {
         int err = -1;
         if (mObserver != null) {
-            Log.d(TAG, "performRestore() called during active restore");
+            Log.d(TAG, "restoreAll() called during active restore");
             return -1;
         }
         mObserver = new RestoreObserverWrapper(mContext, observer);
         try {
-            err = mBinder.performRestore(token, mObserver);
+            err = mBinder.restoreAll(token, mObserver);
         } catch (RemoteException e) {
-            Log.d(TAG, "Can't contact server to perform restore");
+            Log.d(TAG, "Can't contact server to restore");
+        }
+        return err;
+    }
+
+    /**
+     * Restore a single application from backup.  The data will be restored from the
+     * current backup dataset if the given package has stored data there, or from
+     * the dataset used during the last full device setup operation if the current
+     * backup dataset has no matching data.  If no backup data exists for this package
+     * in either source, a nonzero value will be returned.
+     *
+     * @return Zero on success; nonzero on error.  The observer will only receive
+     *   progress callbacks if this method returned zero.
+     * @param packageName The name of the package whose data to restore.  If this is
+     *   not the name of the caller's own package, then the android.permission.BACKUP
+     *   permission must be held.
+     * @param observer If non-null, this binder points to an object that will receive
+     *   progress callbacks during the restore operation.
+     */
+    public int restorePackage(String packageName, RestoreObserver observer) {
+        int err = -1;
+        if (mObserver != null) {
+            Log.d(TAG, "restorePackage() called during active restore");
+            return -1;
+        }
+        mObserver = new RestoreObserverWrapper(mContext, observer);
+        try {
+            err = mBinder.restorePackage(packageName, mObserver);
+        } catch (RemoteException e) {
+            Log.d(TAG, "Can't contact server to restore package");
         }
         return err;
     }
@@ -87,7 +118,7 @@
      *
      * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
      *   even if {@link #getAvailableRestoreSets()} or
-     *   {@link #performRestore(long, RestoreObserver)} failed.
+     *   {@link #restorePackage(long, String, RestoreObserver)} failed.
      */
     public void endRestoreSession() {
         try {
diff --git a/core/java/android/gesture/Gesture.java b/core/java/android/gesture/Gesture.java
index d71344c..300cd28 100755
--- a/core/java/android/gesture/Gesture.java
+++ b/core/java/android/gesture/Gesture.java
@@ -293,7 +293,7 @@
             } catch (IOException e) {
                 Log.e(GestureConstants.LOG_TAG, "Error reading Gesture from parcel:", e);
             } finally {
-                GestureUtilities.closeStream(inStream);
+                GestureUtils.closeStream(inStream);
             }
 
             if (gesture != null) {
@@ -322,8 +322,8 @@
         } catch (IOException e) {
             Log.e(GestureConstants.LOG_TAG, "Error writing Gesture to parcel:", e);
         } finally {
-            GestureUtilities.closeStream(outStream);
-            GestureUtilities.closeStream(byteStream);
+            GestureUtils.closeStream(outStream);
+            GestureUtils.closeStream(byteStream);
         }
 
         if (result) {
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 30ecf5a..b6c260f 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -638,7 +638,7 @@
 
                 if (mTotalLength > mGestureStrokeLengthThreshold) {
                     final OrientedBoundingBox box =
-                            GestureUtilities.computeOrientedBoundingBox(mStrokeBuffer);
+                            GestureUtils.computeOrientedBoundingBox(mStrokeBuffer);
 
                     float angle = Math.abs(box.orientation);
                     if (angle > 90) {
diff --git a/core/java/android/gesture/GestureStore.java b/core/java/android/gesture/GestureStore.java
index 11a94d1..11b5044 100644
--- a/core/java/android/gesture/GestureStore.java
+++ b/core/java/android/gesture/GestureStore.java
@@ -264,7 +264,7 @@
 
             mChanged = false;
         } finally {
-            if (closeStream) GestureUtilities.closeStream(out);
+            if (closeStream) GestureUtils.closeStream(out);
         }
     }
 
@@ -299,7 +299,7 @@
                 Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms");
             }
         } finally {
-            if (closeStream) GestureUtilities.closeStream(in);
+            if (closeStream) GestureUtils.closeStream(in);
         }
     }
 
diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java
index c3ddb28..1d0f0fe 100644
--- a/core/java/android/gesture/GestureStroke.java
+++ b/core/java/android/gesture/GestureStroke.java
@@ -159,15 +159,15 @@
      * @return the path
      */
     public Path toPath(float width, float height, int numSample) {
-        final float[] pts = GestureUtilities.temporalSampling(this, numSample);
+        final float[] pts = GestureUtils.temporalSampling(this, numSample);
         final RectF rect = boundingBox;
 
-        GestureUtilities.translate(pts, -rect.left, -rect.top);
+        GestureUtils.translate(pts, -rect.left, -rect.top);
         
         float sx = width / rect.width();
         float sy = height / rect.height();
         float scale = sx > sy ? sy : sx;
-        GestureUtilities.scale(pts, scale, scale);
+        GestureUtils.scale(pts, scale, scale);
 
         float mX = 0;
         float mY = 0;
@@ -241,6 +241,6 @@
      * @return OrientedBoundingBox
      */
     public OrientedBoundingBox computeOrientedBoundingBox() {
-        return GestureUtilities.computeOrientedBoundingBox(points);
+        return GestureUtils.computeOrientedBoundingBox(points);
     }
 }
diff --git a/core/java/android/gesture/GestureUtilities.java b/core/java/android/gesture/GestureUtils.java
similarity index 99%
rename from core/java/android/gesture/GestureUtilities.java
rename to core/java/android/gesture/GestureUtils.java
index 9d95ce4..dd221fc 100755
--- a/core/java/android/gesture/GestureUtilities.java
+++ b/core/java/android/gesture/GestureUtils.java
@@ -36,12 +36,12 @@
  * distances between two gestures).
  * </ul>
  */
-public final class GestureUtilities {
+public final class GestureUtils {
   
     private static final float SCALING_THRESHOLD = 0.26f;
     private static final float NONUNIFORM_SCALE = (float) Math.sqrt(2);
     
-    private GestureUtilities() {
+    private GestureUtils() {
     }
 
     /**
diff --git a/core/java/android/gesture/Instance.java b/core/java/android/gesture/Instance.java
index bb0b340..02a6519 100755
--- a/core/java/android/gesture/Instance.java
+++ b/core/java/android/gesture/Instance.java
@@ -84,13 +84,13 @@
     }
 
     private static float[] spatialSampler(Gesture gesture) {
-        return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE, false);
+        return GestureUtils.spatialSampling(gesture, PATCH_SAMPLE_SIZE, false);
     }
 
     private static float[] temporalSampler(int orientationType, Gesture gesture) {
-        float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
+        float[] pts = GestureUtils.temporalSampling(gesture.getStrokes().get(0),
                 SEQUENCE_SAMPLE_SIZE);
-        float[] center = GestureUtilities.computeCentroid(pts);
+        float[] center = GestureUtils.computeCentroid(pts);
         float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
 
         float adjustment = -orientation;
@@ -104,8 +104,8 @@
             }
         }
 
-        GestureUtilities.translate(pts, -center[0], -center[1]);
-        GestureUtilities.rotate(pts, adjustment);
+        GestureUtils.translate(pts, -center[0], -center[1]);
+        GestureUtils.rotate(pts, adjustment);
 
         return pts;
     }
diff --git a/core/java/android/gesture/InstanceLearner.java b/core/java/android/gesture/InstanceLearner.java
index 9987e69..7224ded 100644
--- a/core/java/android/gesture/InstanceLearner.java
+++ b/core/java/android/gesture/InstanceLearner.java
@@ -53,9 +53,9 @@
             }
             double distance;
             if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
-                distance = GestureUtilities.minimumCosineDistance(sample.vector, vector, orientationType);
+                distance = GestureUtils.minimumCosineDistance(sample.vector, vector, orientationType);
             } else {
-                distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);
+                distance = GestureUtils.squaredEuclideanDistance(sample.vector, vector);
             }
             double weight;
             if (distance == 0) {
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 0c6bb1a..8eed9f7 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -287,6 +287,7 @@
     static private class SensorThread {
 
         Thread mThread;
+        boolean mSensorsReady;
 
         SensorThread() {
             // this gets to the sensor module. We can have only one per process.
@@ -299,17 +300,28 @@
         }
 
         // must be called with sListeners lock
-        void startLocked(ISensorService service) {
+        boolean startLocked(ISensorService service) {
             try {
                 if (mThread == null) {
                     Bundle dataChannel = service.getDataChannel();
-                    mThread = new Thread(new SensorThreadRunnable(dataChannel),
-                            SensorThread.class.getName());
-                    mThread.start();
+                    if (dataChannel != null) {
+                        mSensorsReady = false;
+                        SensorThreadRunnable runnable = new SensorThreadRunnable(dataChannel);
+                        Thread thread = new Thread(runnable, SensorThread.class.getName());
+                        thread.start();
+                        synchronized (runnable) {
+                            while (mSensorsReady == false) {
+                                runnable.wait();
+                            }
+                        }
+                        mThread = thread;
+                    }
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException in startLocked: ", e);
+            } catch (InterruptedException e) {
             }
+            return mThread == null ? false : true;
         }
 
         private class SensorThreadRunnable implements Runnable {
@@ -319,13 +331,9 @@
             }
 
             private boolean open() {
-                if (mDataChannel == null) {
-                    Log.e(TAG, "mDataChannel == NULL, exiting");
-                    synchronized (sListeners) {
-                        mThread = null;
-                    }
-                    return false;
-                }
+                // NOTE: this cannot synchronize on sListeners, since
+                // it's held in the main thread at least until we
+                // return from here.
 
                 // this thread is guaranteed to be unique
                 Parcelable[] pfds = mDataChannel.getParcelableArray("fds");
@@ -370,6 +378,12 @@
                     return;
                 }
 
+                synchronized (this) {
+                    // we've open the driver, we're ready to open the sensors
+                    mSensorsReady = true;
+                    this.notify();
+                }
+
                 while (true) {
                     // wait for an event
                     final int sensor = sensors_data_poll(values, status, timestamp);
@@ -907,14 +921,18 @@
                 String name = sensor.getName();
                 int handle = sensor.getHandle();
                 if (l == null) {
+                    result = false;
                     l = new ListenerDelegate(listener, sensor, handler);
-                    result = mSensorService.enableSensor(l, name, handle, delay);
-                    if (result) {
-                        sListeners.add(l);
-                        sListeners.notify();
-                    }
+                    sListeners.add(l);
                     if (!sListeners.isEmpty()) {
-                        sSensorThread.startLocked(mSensorService);
+                        result = sSensorThread.startLocked(mSensorService);
+                        if (result) {
+                            result = mSensorService.enableSensor(l, name, handle, delay);
+                            if (!result) {
+                                // there was an error, remove the listeners
+                                sListeners.remove(l);
+                            }
+                        }
                     }
                 } else {
                     result = mSensorService.enableSensor(l, name, handle, delay);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 62e9f1f..ad8e2bf 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -54,7 +54,7 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static long getMobileTxPkts() {
+    public static long getMobileTxPackets() {
         return getMobileStat(MOBILE_TX_PACKETS);
     }
 
@@ -64,7 +64,7 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static long getMobileRxPkts() {
+    public static long getMobileRxPackets() {
         return getMobileStat(MOBILE_RX_PACKETS);
     }
 
@@ -94,7 +94,7 @@
      * @return the number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static long getTotalTxPkts() {
+    public static long getTotalTxPackets() {
         return getTotalStat("tx_packets");
     }
 
@@ -104,7 +104,7 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static long getTotalRxPkts() {
+    public static long getTotalRxPackets() {
         return getTotalStat("rx_packets");
     }
 
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index cb39f7d..9d8bfd9 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -41,7 +41,6 @@
      * It will try to be tolerant of broken syntax instead of
      * returning an error.
      *
-     * @hide
      */
     public static void tokenize(CharSequence text, Collection<Rfc822Token> out) {
         StringBuilder name = new StringBuilder();
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2b8ddc4..46d6352 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -237,4 +237,8 @@
 
     <!-- Component name of the service providing geocoder API support. -->
     <string name="config_geocodeProvider">@null</string>
+
+    <!-- Flag indicating whether headset events are used by kernel to indicate
+    TTY mode changes. -->
+    <bool name="tty_mode_uses_headset_events">false</bool>
 </resources>
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
new file mode 100644
index 0000000..b7ae4a9
--- /dev/null
+++ b/native/graphics/jni/Android.mk
@@ -0,0 +1,36 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PRELINK_MODULE := false
+
+# setup for skia optimizations
+#
+ifneq ($(ARCH_ARM_HAVE_VFP),true)
+	LOCAL_CFLAGS += -DSK_SOFTWARE_FLOAT
+endif
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+	LOCAL_CFLAGS += -D__ARM_HAVE_NEON
+endif
+
+# our source files
+#
+LOCAL_SRC_FILES:= \
+	bitmap.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid_runtime \
+    libskia
+
+LOCAL_C_INCLUDES += \
+	external/skia/include/core \
+	frameworks/base/native/include \
+	frameworks/base/core/jni/android/graphics \
+	dalvik/libnativehelper/include/nativehelper
+
+LOCAL_MODULE:= libjnigraphics
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
new file mode 100644
index 0000000..fd73430
--- /dev/null
+++ b/native/graphics/jni/bitmap.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/bitmap.h>
+#include <GraphicsJNI.h>
+
+int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
+                          AndroidBitmapInfo* info) {
+    if (NULL == env || NULL == jbitmap) {
+        return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+    }
+
+    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    if (NULL == bm) {
+        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+    }
+
+    if (info) {
+        info->width     = bm->width();
+        info->height    = bm->height();
+        info->stride    = bm->rowBytes();
+        info->flags     = 0;
+
+        switch (bm->config()) {
+            case SkBitmap::kARGB_8888_Config:
+                info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
+                break;
+            case SkBitmap::kRGB_565_Config:
+                info->format = ANDROID_BITMAP_FORMAT_RGB_565;
+                break;
+            case SkBitmap::kARGB_4444_Config:
+                info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
+                break;
+            case SkBitmap::kA8_Config:
+                info->format = ANDROID_BITMAP_FORMAT_A_8;
+                break;
+            default:
+                info->format = ANDROID_BITMAP_FORMAT_NONE;
+                break;
+        }
+    }
+    return ANDROID_BITMAP_RESUT_SUCCESS;
+}
+
+int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
+    if (NULL == env || NULL == jbitmap) {
+        return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+    }
+
+    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    if (NULL == bm) {
+        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+    }
+
+    bm->lockPixels();
+    void* addr = bm->getPixels();
+    if (NULL == addr) {
+        bm->unlockPixels();
+        return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
+    }
+
+    if (addrPtr) {
+        *addrPtr = addr;
+    }
+    return ANDROID_BITMAP_RESUT_SUCCESS;
+}
+
+int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
+    if (NULL == env || NULL == jbitmap) {
+        return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+    }
+
+    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    if (NULL == bm) {
+        return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+    }
+
+    bm->unlockPixels();
+    return ANDROID_BITMAP_RESUT_SUCCESS;
+}
+
diff --git a/native/include/android/bitmap.h b/native/include/android/bitmap.h
new file mode 100644
index 0000000..5078277
--- /dev/null
+++ b/native/include/android/bitmap.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BITMAP_H
+#define ANDROID_BITMAP_H
+
+#include <stdint.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ANDROID_BITMAP_RESUT_SUCCESS            0
+#define ANDROID_BITMAP_RESULT_BAD_PARAMETER     -1
+#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION     -2
+#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3
+
+enum AndroidBitmapFormat {
+    ANDROID_BITMAP_FORMAT_NONE      = 0,
+    ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
+    ANDROID_BITMAP_FORMAT_RGB_565   = 4,
+    ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
+    ANDROID_BITMAP_FORMAT_A_8       = 8,
+};
+
+typedef struct {
+    uint32_t    width;
+    uint32_t    height;
+    uint32_t    stride;
+    int32_t     format;
+    uint32_t    flags;      // 0 for now
+} AndroidBitmapInfo;
+
+/**
+ * Given a java bitmap object, fill out the AndroidBitmap struct for it.
+ * If the call fails, the info parameter will be ignored
+ */
+int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
+                          AndroidBitmapInfo* info);
+
+/**
+ * Given a java bitmap object, attempt to lock the pixel address.
+ * Locking will ensure that the memory for the pixels will not move
+ * until the unlockPixels call, and ensure that, if the pixels had been
+ * previously purged, they will have been restored.
+ *
+ * If this call succeeds, it must be balanced by a call to
+ * AndroidBitmap_unlockPixels, after which time the address of the pixels should
+ * no longer be used.
+ *
+ * If this succeeds, *addrPtr will be set to the pixel address. If the call
+ * fails, addrPtr will be ignored.
+ */
+int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
+
+/**
+ * Call this to balanace a successful call to AndroidBitmap_lockPixels
+ */
+int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 0c1e0602..6795bdd 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -176,11 +176,21 @@
         public IBackupTransport transport;
         public IRestoreObserver observer;
         public long token;
+        public PackageInfo pkgInfo;
+
+        RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
+                long _token, PackageInfo _pkg) {
+            transport = _transport;
+            observer = _obs;
+            token = _token;
+            pkgInfo = _pkg;
+        }
 
         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
             transport = _transport;
             observer = _obs;
             token = _token;
+            pkgInfo = null;
         }
     }
 
@@ -210,10 +220,16 @@
     File mJournalDir;
     File mJournal;
 
-    // Keep a log of all the apps we've ever backed up
+    // Keep a log of all the apps we've ever backed up, and what the
+    // dataset tokens are for both the current backup dataset and
+    // the ancestral dataset.
     private File mEverStored;
     HashSet<String> mEverStoredApps = new HashSet<String>();
 
+    File mTokenFile;
+    long mAncestralToken = 0;
+    long mCurrentToken = 0;
+
     // Persistently track the need to do a full init
     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
@@ -277,7 +293,7 @@
                 RestoreParams params = (RestoreParams)msg.obj;
                 Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
                 (new PerformRestoreTask(params.transport, params.observer,
-                        params.token)).run();
+                        params.token, params.pkgInfo)).run();
                 break;
             }
 
@@ -475,6 +491,16 @@
     private void initPackageTracking() {
         if (DEBUG) Log.v(TAG, "Initializing package tracking");
 
+        // Remember our ancestral dataset
+        mTokenFile = new File(mBaseStateDir, "ancestral");
+        try {
+            RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
+            mAncestralToken = tf.readLong();
+            mCurrentToken = tf.readLong();
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to read token file", e);
+        }
+
         // Keep a log of what apps we've ever backed up.  Because we might have
         // rebooted in the middle of an operation that was removing something from
         // this log, we sanity-check its contents here and reconstruct it.
@@ -607,6 +633,9 @@
             mEverStoredApps.clear();
             mEverStored.delete();
 
+            mCurrentToken = 0;
+            writeRestoreTokens();
+
             // Remove all the state files
             for (File sf : stateFileDir.listFiles()) {
                 // ... but don't touch the needs-init sentinel
@@ -880,7 +909,7 @@
         addPackageParticipantsLockedInner(packageName, allApps);
     }
 
-    // Called from the backup thread: record that the given app has been successfully
+    // Called from the backup task: record that the given app has been successfully
     // backed up at least once
     void logBackupComplete(String packageName) {
         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
@@ -938,6 +967,18 @@
         }
     }
 
+    // Record the current and ancestral backup tokens persistently
+    void writeRestoreTokens() {
+        try {
+            RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
+            af.writeLong(mAncestralToken);
+            af.writeLong(mCurrentToken);
+            af.close();
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to write token file:", e);
+        }
+    }
+
     // Return the given transport
     private IBackupTransport getTransport(String transportName) {
         synchronized (mTransports) {
@@ -1154,6 +1195,16 @@
                 Log.e(TAG, "Error in backup thread", e);
                 status = BackupConstants.TRANSPORT_ERROR;
             } finally {
+                // If everything actually went through and this is the first time we've
+                // done a backup, we can now record what the current backup dataset token
+                // is.
+                if ((mCurrentToken == 0) && (status != BackupConstants.TRANSPORT_OK)) {
+                    try {
+                        mCurrentToken = mTransport.getCurrentRestoreSet();
+                    } catch (RemoteException e) { /* cannot happen */ }
+                    writeRestoreTokens();
+                }
+
                 // If things went wrong, we need to re-stage the apps we had expected
                 // to be backing up in this pass.  This journals the package names in
                 // the current active pending-backup file, not in the we are holding
@@ -1395,6 +1446,7 @@
         private IBackupTransport mTransport;
         private IRestoreObserver mObserver;
         private long mToken;
+        private PackageInfo mTargetPackage;
         private File mStateDir;
 
         class RestoreRequest {
@@ -1408,11 +1460,11 @@
         }
 
         PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
-                long restoreSetToken) {
+                long restoreSetToken, PackageInfo targetPackage) {
             mTransport = transport;
-            Log.d(TAG, "PerformRestoreThread mObserver=" + mObserver);
             mObserver = observer;
             mToken = restoreSetToken;
+            mTargetPackage = targetPackage;
 
             try {
                 mStateDir = new File(mBaseStateDir, transport.transportDirName());
@@ -1424,7 +1476,8 @@
         public void run() {
             long startRealtime = SystemClock.elapsedRealtime();
             if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
-                    + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken));
+                    + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
+                    + " mTargetPackage=" + mTargetPackage);
             /**
              * Restore sequence:
              *
@@ -1441,7 +1494,7 @@
              *
              * On errors, we try our best to recover and move on to the next
              * application, but if necessary we abort the whole operation --
-             * the user is waiting, after al.
+             * the user is waiting, after all.
              */
 
             int error = -1; // assume error
@@ -1459,7 +1512,12 @@
                 restorePackages.add(omPackage);
 
                 List<PackageInfo> agentPackages = allAgentPackages();
-                restorePackages.addAll(agentPackages);
+                if (mTargetPackage == null) {
+                    restorePackages.addAll(agentPackages);
+                } else {
+                    // Just one package to attempt restore of
+                    restorePackages.add(mTargetPackage);
+                }
 
                 // let the observer know that we're running
                 if (mObserver != null) {
@@ -1641,6 +1699,13 @@
                     }
                 }
 
+                // If this was a restoreAll operation, record that this was our
+                // ancestral dataset
+                if (mTargetPackage == null) {
+                    mAncestralToken = mToken;
+                    writeRestoreTokens();
+                }
+
                 // done; we can finally release the wakelock
                 mWakelock.release();
             }
@@ -2219,7 +2284,7 @@
             }
         }
 
-        public synchronized int performRestore(long token, IRestoreObserver observer) {
+        public synchronized int restoreAll(long token, IRestoreObserver observer) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                     "performRestore");
 
@@ -2249,6 +2314,55 @@
             return -1;
         }
 
+        public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
+            if (DEBUG) Log.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
+
+            PackageInfo app = null;
+            try {
+                app = mPackageManager.getPackageInfo(packageName, 0);
+            } catch (NameNotFoundException nnf) {
+                Log.w(TAG, "Asked to restore nonexistent pkg " + packageName);
+                return -1;
+            }
+
+            // If the caller is not privileged and is not coming from the target
+            // app's uid, throw a permission exception back to the caller.
+            int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
+                    Binder.getCallingPid(), Binder.getCallingUid());
+            if ((perm == PackageManager.PERMISSION_DENIED) &&
+                    (app.applicationInfo.uid != Binder.getCallingUid())) {
+                Log.w(TAG, "restorePackage: bad packageName=" + packageName
+                        + " or calling uid=" + Binder.getCallingUid());
+                throw new SecurityException("No permission to restore other packages");
+            }
+
+            // So far so good; we're allowed to try to restore this package.  Now
+            // check whether there is data for it in the current dataset, falling back
+            // to the ancestral dataset if not.
+            long token = mAncestralToken;
+            synchronized (mQueueLock) {
+                if (mEverStoredApps.contains(packageName)) {
+                    token = mCurrentToken;
+                }
+            }
+
+            // If we didn't come up with a place to look -- no ancestral dataset and
+            // the app has never been backed up from this device -- there's nothing
+            // to do but return failure.
+            if (token == 0) {
+                return -1;
+            }
+
+            // Ready to go:  enqueue the restore request and claim success
+            long oldId = Binder.clearCallingIdentity();
+            mWakelock.acquire();
+            Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+            msg.obj = new RestoreParams(mRestoreTransport, observer, token, app);
+            mBackupHandler.sendMessage(msg);
+            Binder.restoreCallingIdentity(oldId);
+            return 0;
+        }
+
         public synchronized void endRestoreSession() {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                     "endRestoreSession");
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9d69564..c94450b 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -53,6 +53,19 @@
     private final Context mContext;
     private final WakeLock mWakeLock;  // held while there is a pending route change
 
+    private boolean mHandleTTY;
+    private int mTTYState;
+    private AudioManager mAudioManager = null;
+
+    // special use of bits in headset state received from kernel made by some
+    // platforms to indicate changes in TTY mode.
+    private static final int BIT_TTY_OFF = 0;
+    private static final int BIT_TTY_FULL = (1 << 2);
+    private static final int BIT_TTY_VCO = (1 << 5);
+    private static final int BIT_TTY_HCO = (1 << 6);
+    private static final int TTY_BITS_MASK = (BIT_TTY_FULL | BIT_TTY_VCO | BIT_TTY_HCO);
+
+
     public HeadsetObserver(Context context) {
         mContext = context;
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -61,6 +74,11 @@
 
         startObserving(HEADSET_UEVENT_MATCH);
 
+        // read settings for TTY mode indication method
+        mHandleTTY = context.getResources().getBoolean(
+                com.android.internal.R.bool.tty_mode_uses_headset_events);
+        mTTYState = BIT_TTY_OFF;
+
         init();  // set initial status
     }
 
@@ -100,6 +118,39 @@
     }
 
     private synchronized final void update(String newName, int newState) {
+        // handle TTY state change first
+        if (mHandleTTY) {
+            int ttyState = newState  & TTY_BITS_MASK;
+            if (ttyState != mTTYState) {
+                String ttyMode;
+
+                switch (ttyState) {
+                case BIT_TTY_FULL:
+                    ttyMode = "tty_full";
+                    break;
+                case BIT_TTY_VCO:
+                    ttyMode = "tty_vco";
+                    break;
+                case BIT_TTY_HCO:
+                    ttyMode = "tty_hco";
+                    break;
+                case BIT_TTY_OFF:
+                    ttyMode = "tty_off";
+                    break;
+                default:
+                    ttyMode = "tty_invalid";
+                    break;
+
+                }
+                if (ttyMode != "tty_invalid") {
+                    mTTYState = ttyState;
+                    if (mAudioManager == null) {
+                        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+                    }
+                    mAudioManager.setParameters("tty_mode="+ttyMode);
+                }
+            }
+        }
         // Retain only relevant bits
         int headsetState = newState & SUPPORTED_HEADSETS;
         int newOrOld = headsetState | mHeadsetState;
diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java
index 0834405..ac3445e 100644
--- a/services/java/com/android/server/NetStatService.java
+++ b/services/java/com/android/server/NetStatService.java
@@ -27,11 +27,11 @@
     }
 
     public long getMobileTxPackets() {
-        return TrafficStats.getMobileTxPkts();
+        return TrafficStats.getMobileTxPackets();
     }
 
     public long getMobileRxPackets() {
-        return TrafficStats.getMobileRxPkts();
+        return TrafficStats.getMobileRxPackets();
     }
 
     public long getMobileTxBytes() {
@@ -43,11 +43,11 @@
     }
 
     public long getTotalTxPackets() {
-        return TrafficStats.getTotalTxPkts();
+        return TrafficStats.getTotalTxPackets();
     }
 
     public long getTotalRxPackets() {
-        return TrafficStats.getTotalRxPkts();
+        return TrafficStats.getTotalRxPackets();
     }
 
     public long getTotalTxBytes() {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index ab29575..55041fb 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -687,7 +687,8 @@
                     && (oldData == null
                         || oldData.tickerText == null
                         || !CharSequences.equals(oldData.tickerText, n.tickerText))) {
-                if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+                if (0 == (mDisabled & 
+                    (StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
                     mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText);
                 }
             }
@@ -1698,6 +1699,10 @@
                     setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
                 }
             }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                mTicker.halt();
+            }
         }
     }
 
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index c2548b9..70d0e78 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -26,6 +26,8 @@
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
     <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
     <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
diff --git a/tests/AndroidTests/res/raw/install b/tests/AndroidTests/res/raw/install
new file mode 100644
index 0000000..2ee1f3c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install
Binary files differ
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
new file mode 100755
index 0000000..163ddd5
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.Uri;
+import android.os.FileUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageStats;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+
+public class PackageManagerTests extends AndroidTestCase {
+    private static final boolean localLOGV = false;
+    public static final String TAG="PackageManagerTests";
+    public final long MAX_WAIT_TIME=60*1000;
+    public final long WAIT_TIME_INCR=10*1000;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    private class PackageInstallObserver extends IPackageInstallObserver.Stub {
+        public int returnCode;
+        private boolean doneFlag = false;
+
+        public void packageInstalled(String packageName, int returnCode) {
+            synchronized(this) {
+                this.returnCode = returnCode;
+                doneFlag = true;
+                notifyAll();
+            }
+        }
+
+        public boolean isDone() {
+            return doneFlag;
+        }
+    }
+
+    abstract class GenericReceiver extends BroadcastReceiver {
+        private boolean doneFlag = false;
+        boolean received = false;
+        Intent intent;
+        IntentFilter filter;
+        abstract boolean notifyNow(Intent intent);
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (notifyNow(intent)) {
+                synchronized (this) {
+                    received = true;
+                    doneFlag = true;
+                    this.intent = intent;
+                    notifyAll();
+                }
+            }
+        }
+
+        public boolean isDone() {
+            return doneFlag;
+        }
+
+        public void setFilter(IntentFilter filter) {
+            this.filter = filter;
+        }
+    }
+
+    class InstallReceiver extends GenericReceiver {
+        String pkgName;
+
+        InstallReceiver(String pkgName) {
+            this.pkgName = pkgName;
+            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+            filter.addDataScheme("package");
+            super.setFilter(filter);
+        }
+
+        public boolean notifyNow(Intent intent) {
+            String action = intent.getAction();
+            if (!Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+                return false;
+            }
+            Uri data = intent.getData();
+            String installedPkg = data.getEncodedSchemeSpecificPart();
+            if (pkgName.equals(installedPkg)) {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    PackageManager getPm() {
+        return mContext.getPackageManager();
+    }
+
+    public boolean invokeInstallPackage(Uri packageURI, int flags,
+            final String pkgName, GenericReceiver receiver) throws Exception {
+        PackageInstallObserver observer = new PackageInstallObserver();
+        final boolean received = false;
+        mContext.registerReceiver(receiver, receiver.filter);
+        try {
+            // Wait on observer
+            synchronized(observer) {
+                    getPm().installPackage(packageURI, observer, flags, null);
+                    long waitTime = 0;
+                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                        observer.wait(WAIT_TIME_INCR);
+                        waitTime += WAIT_TIME_INCR;
+                    }
+                    if(!observer.isDone()) {
+                        throw new Exception("Timed out waiting for packageInstalled callback");
+                    }
+                    if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+                        return false;
+                    }
+                    synchronized (receiver) {
+                    // Verify we received the broadcast
+                    waitTime = 0;
+                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                        receiver.wait(WAIT_TIME_INCR);
+                        waitTime += WAIT_TIME_INCR;
+                    }
+                    if(!receiver.isDone()) {
+                        throw new Exception("Timed out waiting for PACKAGE_ADDED notification");
+                    }
+                    return receiver.received;
+                }
+            }
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    Uri getInstallablePackage(int fileResId, File outFile) {
+        Resources res = mContext.getResources();
+        InputStream is = null;
+        try {
+            is = res.openRawResource(fileResId);
+        } catch (NotFoundException e) {
+            failStr("Failed to load resource with id: " + fileResId);
+        }
+        FileUtils.setPermissions(outFile.getPath(),
+                FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO,
+                -1, -1);
+        assertTrue(FileUtils.copyToFile(is, outFile));
+        FileUtils.setPermissions(outFile.getPath(),
+                FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO,
+                -1, -1);
+        return Uri.fromFile(outFile);
+    }
+
+    private PackageParser.Package parsePackage(Uri packageURI) {
+        final String archiveFilePath = packageURI.getPath();
+        PackageParser packageParser = new PackageParser(archiveFilePath);
+        File sourceFile = new File(archiveFilePath);
+        DisplayMetrics metrics = new DisplayMetrics();
+        metrics.setToDefaults();
+        return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+    }
+
+    private void assertInstall(String pkgName, int flags) {
+        try {
+        ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
+        assertNotNull(info);
+        assertEquals(pkgName, info.packageName);
+        File dataDir = Environment.getDataDirectory();
+        String appInstallPath = new File(dataDir, "app").getPath();
+        String drmInstallPath = new File(dataDir, "app-private").getPath();
+        File srcDir = new File(info.sourceDir);
+        String srcPath = srcDir.getParent();
+        File publicSrcDir = new File(info.publicSourceDir);
+        String publicSrcPath = publicSrcDir.getParent();
+
+        if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
+            assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+            assertEquals(srcPath, drmInstallPath);
+            assertEquals(publicSrcPath, appInstallPath);
+        } else {
+            assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+            if ((flags & PackageManager.INSTALL_ON_SDCARD) != 0) {
+                assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+                // Hardcoded for now
+                assertTrue(srcPath.startsWith("/asec"));
+                assertTrue(publicSrcPath.startsWith("/asec"));
+            } else {
+                assertEquals(srcPath, appInstallPath);
+                assertEquals(publicSrcPath, appInstallPath);
+                assertFalse((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+            }
+        }
+        } catch (NameNotFoundException e) {
+            failStr("failed with exception : " + e);
+        }
+    }
+
+    class InstallParams {
+        String outFileName;
+        Uri packageURI;
+        PackageParser.Package pkg;
+        InstallParams(PackageParser.Package pkg, String outFileName, Uri packageURI) {
+            this.outFileName = outFileName;
+            this.packageURI = packageURI;
+            this.pkg = pkg;
+        }
+    }
+
+    /*
+     * Utility function that reads a apk bundled as a raw resource
+     * copies it into own data directory and invokes
+     * PackageManager api to install it.
+     */
+    public InstallParams installFromRawResource(int flags, boolean cleanUp) {
+        String outFileName = "install.apk";
+        File filesDir = mContext.getFilesDir();
+        File outFile = new File(filesDir, outFileName);
+        Uri packageURI = getInstallablePackage(R.raw.install, outFile);
+        PackageParser.Package pkg = parsePackage(packageURI);
+        assertNotNull(pkg);
+        InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+        try {
+            try {
+                assertTrue(invokeInstallPackage(packageURI, flags,
+                        pkg.packageName, receiver));
+            } catch (Exception e) {
+                failStr("Failed with exception : " + e);
+            }
+            // Verify installed information
+            assertInstall(pkg.packageName, flags);
+            return new InstallParams(pkg, outFileName, packageURI);
+        } finally {
+            if (cleanUp) {
+                getPm().deletePackage(pkg.packageName, null, 0);
+                if (outFile != null && outFile.exists()) {
+                    outFile.delete();
+                }
+            }
+        }
+    }
+
+    @MediumTest
+    public void testInstallNormalInternal() {
+        installFromRawResource(0, true);
+    }
+
+    @MediumTest
+    public void testInstallFwdLockedInternal() {
+        installFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
+    }
+
+    @MediumTest
+    public void testInstallSdcard() {
+        installFromRawResource(PackageManager.INSTALL_ON_SDCARD, true);
+    }
+
+    /* ------------------------- Test replacing packages --------------*/
+    class ReplaceReceiver extends GenericReceiver {
+        String pkgName;
+        boolean removed = false;
+
+        ReplaceReceiver(String pkgName) {
+            this.pkgName = pkgName;
+            filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+            super.setFilter(filter);
+        }
+
+        public boolean notifyNow(Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+                    Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+                Uri data = intent.getData();
+                String installedPkg = data.getEncodedSchemeSpecificPart();
+                if (pkgName.equals(installedPkg)) {
+                    if (removed) {
+                        return true;
+                    } else {
+                        removed = true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /*
+     * Utility function that reads a apk bundled as a raw resource
+     * copies it into own data directory and invokes
+     * PackageManager api to install first and then replace it
+     * again.
+     */
+    public void replaceFromRawResource(int flags) {
+        InstallParams ip = installFromRawResource(flags, false);
+        boolean result = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
+        GenericReceiver receiver;
+        if (result) {
+            receiver = new ReplaceReceiver(ip.pkg.packageName);
+        } else {
+            receiver = new InstallReceiver(ip.pkg.packageName);
+        }
+        try {
+            try {
+                assertEquals(invokeInstallPackage(ip.packageURI, flags,
+                        ip.pkg.packageName, receiver), result);
+                if (result) {
+                    assertInstall(ip.pkg.packageName, flags);
+                }
+            } catch (Exception e) {
+                failStr("Failed with exception : " + e);
+            }
+        } finally {
+            getPm().deletePackage(ip.pkg.packageName, null, 0);
+            File outFile = new File(ip.outFileName);
+            if (outFile != null && outFile.exists()) {
+                outFile.delete();
+            }
+        }
+    }
+
+    @MediumTest
+    public void testReplaceFailNormalInternal() {
+        replaceFromRawResource(0);
+    }
+
+    @MediumTest
+    public void testReplaceFailFwdLockedInternal() {
+        replaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
+    }
+
+    @MediumTest
+    public void testReplaceFailSdcard() {
+        replaceFromRawResource(PackageManager.INSTALL_ON_SDCARD);
+    }
+
+    void failStr(String errMsg) {
+        Log.w(TAG, "errMsg="+errMsg);
+        fail(errMsg);
+    }
+    void failStr(Exception e) {
+        Log.w(TAG, "e.getMessage="+e.getMessage());
+        Log.w(TAG, "e="+e);
+    }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 275e5cb..06506fb 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -62,6 +62,11 @@
                 mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ALERTS);
             }
         },
+        new Test("Disable Ticker") {
+            public void run() {
+                mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_TICKER);
+            }
+        },
         new Test("Disable Expand in 3 sec.") {
             public void run() {
                 mHandler.postDelayed(new Runnable() {
@@ -80,7 +85,7 @@
                     }, 3000);
             }
         },
-        new Test("Disable Both in 3 sec.") {
+        new Test("Disable Expand + Notifications in 3 sec.") {
             public void run() {
                 mHandler.postDelayed(new Runnable() {
                         public void run() {
@@ -90,7 +95,12 @@
                     }, 3000);
             }
         },
-        new Test("Disable None in 3 sec.") {
+        new Test("Enable everything") {
+            public void run() {
+                mStatusBarManager.disable(0);
+            }
+        },
+        new Test("Enable everything in 3 sec.") {
             public void run() {
                 mHandler.postDelayed(new Runnable() {
                         public void run() {