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