summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ContextImpl.java96
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java34
-rw-r--r--core/java/android/net/Downloads.java627
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java57
-rw-r--r--core/java/android/net/WebAddress.java7
-rw-r--r--core/java/android/os/ICheckinService.aidl35
-rw-r--r--core/java/android/os/IParentalControlCallback.aidl27
-rw-r--r--core/java/android/pim/vcard/VCardComposer.java60
-rw-r--r--core/java/android/pim/vcard/VCardEntry.java25
-rw-r--r--core/java/android/provider/Checkin.java269
-rw-r--r--core/java/android/provider/Settings.java63
-rw-r--r--core/java/android/text/AndroidCharacter.java39
-rw-r--r--core/java/android/text/util/Rfc822Tokenizer.java4
-rw-r--r--core/java/android/util/base64/Base64.java769
-rw-r--r--core/java/android/util/base64/Base64InputStream.java49
-rw-r--r--core/java/android/util/base64/Base64OutputStream.java57
-rw-r--r--core/java/android/view/GestureDetector.java8
-rw-r--r--core/java/android/view/MotionEvent.java100
-rw-r--r--core/java/android/view/VelocityTracker.java59
-rw-r--r--core/java/android/webkit/WebView.java4
-rw-r--r--core/java/android/widget/GridView.java14
-rw-r--r--core/java/android/widget/HorizontalScrollView.java9
-rw-r--r--core/java/android/widget/ScrollView.java9
-rwxr-xr-xcore/java/com/android/internal/app/IMediaContainerService.aidl1
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java182
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java1
-rw-r--r--core/java/com/google/android/net/ParentalControl.java73
-rw-r--r--core/java/com/google/android/net/ParentalControlState.aidl18
-rw-r--r--core/java/com/google/android/net/ParentalControlState.java56
30 files changed, 1473 insertions, 1281 deletions
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 @@ class ContextImpl extends Context {
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 @@ public class Intent implements Parcelable, Cloneable {
* @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 @@ public abstract class PackageManager {
* 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 abstract class PackageManager {
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 abstract class PackageManager {
*/
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.ContentValues;
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 {
- /** @hide */
- private ByUri() {}
+ /**
+ * Download status codes
+ */
- /**
- * 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();
+ /**
+ * This download hasn't started yet
+ */
+ public static final int STATUS_PENDING = 190;
- // 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);
- }
+ /**
+ * This download has started
+ */
+ public static final int STATUS_RUNNING = 192;
- if (cr.insert(android.provider.Downloads.Impl.CONTENT_URI, values) == null) {
- return false;
- }
- return true;
- }
+ /**
+ * 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;
- 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;
- }
+ /**
+ * 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";
- /** @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;
+
+ /**
+ * 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;
/**
- * Column projection for the query to the download manager. This must match
- * with the constants DOWNLOADS_COLUMN_*.
- * @hide
+ * Returns whether the download is completed
+ * @return a boolean whether the download is complete.
*/
- 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,
- };
+ public boolean isComplete() {
+ return android.provider.Downloads.Impl.isStatusCompleted(statusCode);
+ }
/**
- * 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;
+ * 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() {}
/**
- * 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 @@ public final class Downloads {
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 @@ public final class Downloads {
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 @@ public final class Downloads {
/**
* Delete all the downloads for a package/class pair.
- * @pending
*/
public static final void removeAllDownloadsByPackage(
Context context,
@@ -265,21 +296,24 @@ public final class Downloads {
}
/**
- * @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 @@ public final class Downloads {
/** @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 @@ import org.apache.harmony.xnet.provider.jsse.SSLParameters;
* <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 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
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 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
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 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
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 @@ public class WebAddress {
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.Cursor;
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.OutputStream;
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 @@ public class VCardComposer {
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 @@ public class VCardComposer {
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 @@ public class VCardComposer {
}
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 @@ public class VCardComposer {
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 @@ public class VCardComposer {
}
}
- 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 @@ public class VCardEntry {
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 @@ public class VCardEntry {
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 final class Settings {
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 final class Settings {
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 @@ package android.text;
*/
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 class AndroidCharacter
*/
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 @@ public class Rfc822Tokenizer implements MultiAutoCompleteTextView.Tokenizer {
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 @@ public class Rfc822Tokenizer implements MultiAutoCompleteTextView.Tokenizer {
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 088de9f..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 class Base64 {
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;
// --------------------------------------------------------
- // decoding
+ // shared code
// --------------------------------------------------------
- /**
- * 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,
- };
+ /* package */ static abstract class Coder {
+ public byte[] output;
+ public int op;
- /**
- * 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;
+ /**
+ * 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
+ // --------------------------------------------------------
/**
* 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 @@ public class Base64 {
* 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 @@ public class Base64 {
* 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 class Base64 {
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;
-
- public int state; // state number (0 to 6)
- public int value;
-
- final public int[] alphabet;
-
- public DecoderState(int flags, byte[] output) {
+ /* 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,
+ };
+
+ /**
+ * 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;
+
+ /**
+ * 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;
-
- 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;
- }
+ /**
+ * 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 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) {
+ // 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;
+ }
- // 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];
+ // 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.
- switch (state) {
+ int d = alphabet[input[p++] & 0xff];
+
+ 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 @@ public class Base64 {
value = (value << 6) | d;
++state;
} else if (d != SKIP) {
- dstate.state = 6;
+ this.state = 6;
return false;
}
break;
@@ -308,7 +345,7 @@ public class Base64 {
output[op++] = (byte) (value >> 4);
state = 4;
} else if (d != SKIP) {
- dstate.state = 6;
+ this.state = 6;
return false;
}
break;
@@ -330,7 +367,7 @@ public class Base64 {
op += 2;
state = 5;
} else if (d != SKIP) {
- dstate.state = 6;
+ this.state = 6;
return false;
}
break;
@@ -339,41 +376,40 @@ public class Base64 {
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 @@ public class Base64 {
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 @@ public class Base64 {
// --------------------------------------------------------
/**
- * 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 @@ public class Base64 {
* 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 @@ public class Base64 {
* 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 @@ public class Base64 {
* 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 @@ public class Base64 {
}
// 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;
-
- final public byte[] tail;
- public int tailLen;
- public int count;
+ /* 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;
+
+ /**
+ * 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;
+ /**
+ * @return an overestimate for the number of bytes {@code
+ * len} bytes could encode to.
+ */
+ public int maxOutputSize(int len) {
+ return len * 8/5 + 10;
+ }
- int p = offset;
- len += offset;
- int v = -1;
- int count = estate.count;
+ 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;
- // 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.
+ int p = offset;
+ len += offset;
+ int v = -1;
- switch (estate.tailLen) {
- case 0:
- // There was no tail.
- break;
+ // 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.
- 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;
+ switch (tailLen) {
+ case 0:
+ // There was no tail.
+ 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;
- }
+ 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;
- 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;
+ 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 (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 (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) {
+ // 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;
}
- } 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 (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 (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];
+ 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];
+ }
}
- }
- estate.op = op;
- estate.count = count;
+ this.op = op;
+ this.count = count;
+
+ return true;
+ }
}
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 @@ import java.io.InputStream;
* 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 class Base64InputStream extends FilterInputStream {
*/
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 @@ public class Base64InputStream extends FilterInputStream {
if (outputStart >= outputEnd) {
return -1;
} else {
- return outputBuffer[outputStart++];
+ return coder.output[outputStart++];
}
}
@@ -135,36 +124,30 @@ public class Base64InputStream extends FilterInputStream {
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 @@ import java.io.OutputStream;
* 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 class Base64OutputStream extends FilterOutputStream {
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 class Base64OutputStream extends FilterOutputStream {
}
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 @@ public class Base64OutputStream extends FilterOutputStream {
* 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 @@ public class GestureDetector {
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 final class MotionEvent implements Parcelable {
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.
+ * 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_1_DOWN = ACTION_POINTER_DOWN | 0x0000;
+ public static final int ACTION_POINTER_UP = 6;
/**
- * Synonym for {@link #ACTION_POINTER_DOWN} with
- * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done.
+ * 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_2_DOWN = ACTION_POINTER_DOWN | 0x0100;
+ public static final int ACTION_POINTER_INDEX_MASK = 0xff00;
/**
- * Synonym for {@link #ACTION_POINTER_DOWN} with
- * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done.
+ * Bit shift for the action bits holding the pointer index as
+ * defined by {@link #ACTION_POINTER_INDEX_MASK}.
*/
- public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200;
+ public static final int ACTION_POINTER_INDEX_SHIFT = 8;
/**
- * A non-primary pointer has gone up. The bits in
- * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
+ * data index associated with {@link #ACTION_POINTER_DOWN}.
*/
- public static final int ACTION_POINTER_UP = 6;
+ @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;
/**
- * Synonym for {@link #ACTION_POINTER_UP} with
- * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up.
+ * @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 @@ public final class MotionEvent implements Parcelable {
/**
* 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 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
* @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;
+ }
+ 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);
}
- addPoint(p, ev.getX(p), ev.getY(p), time);
+
+ 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;
}
- }
- 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;
+ mLastTouch = touchIndex;
}
/**
@@ -177,10 +190,12 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
// 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 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
* 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 @@ public class WebView extends AbsoluteLayout
}
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 @@ public class GridView extends AbsListView {
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 @@ public class GridView extends AbsListView {
// 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 @@ public class HorizontalScrollView extends FrameLayout {
*/
@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 @@ public class ScrollView extends FrameLayout {
*/
@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 @@ interface IMediaContainerService {
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.app.IActivityManager;
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;
- }
-};