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<android.text.util.Rfc822Token>">
+</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() {