diff options
Diffstat (limited to 'core/java/android')
27 files changed, 950 insertions, 25 deletions
diff --git a/core/java/android/app/AliasActivity.java b/core/java/android/app/AliasActivity.java index 7527a5b..3756529 100644 --- a/core/java/android/app/AliasActivity.java +++ b/core/java/android/app/AliasActivity.java @@ -26,7 +26,8 @@ import android.content.res.XmlResourceParser; import android.os.Bundle; import android.util.AttributeSet; import android.util.Xml; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import java.io.IOException; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 50dcdf9..0e21936 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -17,7 +17,7 @@ package android.app; import com.android.internal.policy.PolicyManager; -import com.android.common.XmlUtils; +import com.android.internal.util.XmlUtils; import com.google.android.collect.Maps; import org.xmlpull.v1.XmlPullParserException; diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index cb6aab6..af68689 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -16,8 +16,6 @@ package android.app; -import com.android.common.Patterns; -import com.android.common.speech.Recognition; import static android.app.SuggestionsAdapter.getColumnString; @@ -48,6 +46,7 @@ import android.text.TextWatcher; import android.util.AndroidRuntimeException; import android.util.AttributeSet; import android.util.Log; +import android.util.Patterns; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.KeyEvent; @@ -820,7 +819,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); - voiceIntent.putExtra(Recognition.EXTRA_CALLING_PACKAGE, + voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity == null ? null : searchActivity.toShortString()); // Add the values that configure forwarding the results diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 607605d..fb3f646 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -34,7 +34,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import java.io.IOException; import java.io.Serializable; diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 023c024..452fd8a 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -34,7 +34,8 @@ import android.util.AndroidException; import android.util.Config; import android.util.Log; import android.util.Printer; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; /** * Structured description of Intent values to be matched. An IntentFilter can diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index fcb910d..5aad3af 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -18,7 +18,7 @@ package android.content; import com.android.internal.os.AtomicFile; import com.android.internal.util.ArrayUtils; -import com.android.common.FastXmlSerializer; +import com.android.internal.util.FastXmlSerializer; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 98aacaa..6599ae5 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -35,7 +35,8 @@ import android.util.Config; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import java.io.File; import java.io.IOException; diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index a885820..b74c073 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -43,7 +43,7 @@ import java.io.IOException; import java.io.FileInputStream; import com.android.internal.os.AtomicFile; -import com.android.common.FastXmlSerializer; +import com.android.internal.util.FastXmlSerializer; import com.google.android.collect.Maps; import com.google.android.collect.Lists; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index a5e39d4..0608cc0 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -17,7 +17,7 @@ package android.content.res; -import com.android.common.XmlUtils; +import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index 2411177..5e90b91 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -24,7 +24,8 @@ import android.util.SparseArray; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; /** * Conveniences for retrieving data out of a compiled string resource. diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 8f0003b..a7fb31d 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -5,7 +5,8 @@ import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import java.util.Arrays; diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index 3c2c30a..ad1bfb2 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -17,7 +17,8 @@ package android.content.res; import android.util.TypedValue; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParserException; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index f959fee..6941e57 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -16,11 +16,12 @@ package android.net; +import com.android.internal.net.DomainNameValidator; + import android.os.SystemProperties; import android.util.Config; import android.util.Log; -import com.android.common.DomainNameValidator; import java.io.IOException; import java.net.InetAddress; diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java index fa13894..a572f60 100644 --- a/core/java/android/net/WebAddress.java +++ b/core/java/android/net/WebAddress.java @@ -16,7 +16,7 @@ package android.net; -import static com.android.common.Patterns.GOOD_IRI_CHAR; +import static android.util.Patterns.GOOD_IRI_CHAR; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java new file mode 100644 index 0000000..3517737 --- /dev/null +++ b/core/java/android/net/http/AndroidHttpClient.java @@ -0,0 +1,447 @@ +/* + * 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.net.http; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpRequestInterceptor; +import org.apache.http.HttpResponse; +import org.apache.http.entity.AbstractHttpEntity; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.protocol.ClientContext; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.params.HttpClientParams; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.client.RequestWrapper; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.BasicHttpContext; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import java.net.URI; + +import android.content.Context; +import android.content.ContentResolver; +import android.net.SSLCertificateSocketFactory; +import android.net.SSLSessionCache; +import android.os.Looper; +import android.util.Log; + +/** + * Subclass of the Apache {@link DefaultHttpClient} that is configured with + * reasonable default settings and registered schemes for Android, and + * also lets the user add {@link HttpRequestInterceptor} classes. + * Don't create this directly, use the {@link #newInstance} factory method. + * + * <p>This client processes cookies but does not retain them by default. + * To retain cookies, simply add a cookie store to the HttpContext:</p> + * + * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre> + */ +public final class AndroidHttpClient implements HttpClient { + + // Gzip of data shorter than this probably won't be worthwhile + public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256; + + private static final String TAG = "AndroidHttpClient"; + + + /** Interceptor throws an exception if the executing thread is blocked */ + private static final HttpRequestInterceptor sThreadCheckInterceptor = + new HttpRequestInterceptor() { + public void process(HttpRequest request, HttpContext context) { + // Prevent the HttpRequest from being sent on the main thread + if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) { + throw new RuntimeException("This thread forbids HTTP requests"); + } + } + }; + + /** + * Create a new HttpClient with reasonable defaults (which you can update). + * + * @param userAgent to report in your HTTP requests + * @param context to use for caching SSL sessions (may be null for no caching) + * @return AndroidHttpClient for you to use for all your requests. + */ + public static AndroidHttpClient newInstance(String userAgent, Context context) { + HttpParams params = new BasicHttpParams(); + + // Turn off stale checking. Our connections break all the time anyway, + // and it's not worth it to pay the penalty of checking every time. + HttpConnectionParams.setStaleCheckingEnabled(params, false); + + // Default connection and socket timeout of 20 seconds. Tweak to taste. + HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); + HttpConnectionParams.setSoTimeout(params, 20 * 1000); + HttpConnectionParams.setSocketBufferSize(params, 8192); + + // Don't handle redirects -- return them to the caller. Our code + // often wants to re-POST after a redirect, which we must do ourselves. + HttpClientParams.setRedirecting(params, false); + + // Use a session cache for SSL sockets + SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context); + + // Set the specified user agent and register standard protocols. + HttpProtocolParams.setUserAgent(params, userAgent); + SchemeRegistry schemeRegistry = new SchemeRegistry(); + schemeRegistry.register(new Scheme("http", + PlainSocketFactory.getSocketFactory(), 80)); + schemeRegistry.register(new Scheme("https", + SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, sessionCache), 443)); + + ClientConnectionManager manager = + new ThreadSafeClientConnManager(params, schemeRegistry); + + // We use a factory method to modify superclass initialization + // parameters without the funny call-a-static-method dance. + return new AndroidHttpClient(manager, params); + } + + /** + * Create a new HttpClient with reasonable defaults (which you can update). + * @param userAgent to report in your HTTP requests. + * @return AndroidHttpClient for you to use for all your requests. + */ + public static AndroidHttpClient newInstance(String userAgent) { + return newInstance(userAgent, null /* session cache */); + } + + private final HttpClient delegate; + + private RuntimeException mLeakedException = new IllegalStateException( + "AndroidHttpClient created and never closed"); + + private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) { + this.delegate = new DefaultHttpClient(ccm, params) { + @Override + protected BasicHttpProcessor createHttpProcessor() { + // Add interceptor to prevent making requests from main thread. + BasicHttpProcessor processor = super.createHttpProcessor(); + processor.addRequestInterceptor(sThreadCheckInterceptor); + processor.addRequestInterceptor(new CurlLogger()); + + return processor; + } + + @Override + protected HttpContext createHttpContext() { + // Same as DefaultHttpClient.createHttpContext() minus the + // cookie store. + HttpContext context = new BasicHttpContext(); + context.setAttribute( + ClientContext.AUTHSCHEME_REGISTRY, + getAuthSchemes()); + context.setAttribute( + ClientContext.COOKIESPEC_REGISTRY, + getCookieSpecs()); + context.setAttribute( + ClientContext.CREDS_PROVIDER, + getCredentialsProvider()); + return context; + } + }; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + if (mLeakedException != null) { + Log.e(TAG, "Leak found", mLeakedException); + mLeakedException = null; + } + } + + /** + * Modifies a request to indicate to the server that we would like a + * gzipped response. (Uses the "Accept-Encoding" HTTP header.) + * @param request the request to modify + * @see #getUngzippedContent + */ + public static void modifyRequestToAcceptGzipResponse(HttpRequest request) { + request.addHeader("Accept-Encoding", "gzip"); + } + + /** + * Gets the input stream from a response entity. If the entity is gzipped + * then this will get a stream over the uncompressed data. + * + * @param entity the entity whose content should be read + * @return the input stream to read from + * @throws IOException + */ + public static InputStream getUngzippedContent(HttpEntity entity) + throws IOException { + InputStream responseStream = entity.getContent(); + if (responseStream == null) return responseStream; + Header header = entity.getContentEncoding(); + if (header == null) return responseStream; + String contentEncoding = header.getValue(); + if (contentEncoding == null) return responseStream; + if (contentEncoding.contains("gzip")) responseStream + = new GZIPInputStream(responseStream); + return responseStream; + } + + /** + * Release resources associated with this client. You must call this, + * or significant resources (sockets and memory) may be leaked. + */ + public void close() { + if (mLeakedException != null) { + getConnectionManager().shutdown(); + mLeakedException = null; + } + } + + public HttpParams getParams() { + return delegate.getParams(); + } + + public ClientConnectionManager getConnectionManager() { + return delegate.getConnectionManager(); + } + + public HttpResponse execute(HttpUriRequest request) throws IOException { + return delegate.execute(request); + } + + public HttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException { + return delegate.execute(request, context); + } + + public HttpResponse execute(HttpHost target, HttpRequest request) + throws IOException { + return delegate.execute(target, request); + } + + public HttpResponse execute(HttpHost target, HttpRequest request, + HttpContext context) throws IOException { + return delegate.execute(target, request, context); + } + + public <T> T execute(HttpUriRequest request, + ResponseHandler<? extends T> responseHandler) + throws IOException, ClientProtocolException { + return delegate.execute(request, responseHandler); + } + + public <T> T execute(HttpUriRequest request, + ResponseHandler<? extends T> responseHandler, HttpContext context) + throws IOException, ClientProtocolException { + return delegate.execute(request, responseHandler, context); + } + + public <T> T execute(HttpHost target, HttpRequest request, + ResponseHandler<? extends T> responseHandler) throws IOException, + ClientProtocolException { + return delegate.execute(target, request, responseHandler); + } + + public <T> T execute(HttpHost target, HttpRequest request, + ResponseHandler<? extends T> responseHandler, HttpContext context) + throws IOException, ClientProtocolException { + return delegate.execute(target, request, responseHandler, context); + } + + /** + * Compress data to send to server. + * Creates a Http Entity holding the gzipped data. + * The data will not be compressed if it is too short. + * @param data The bytes to compress + * @return Entity holding the data + */ + public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver) + throws IOException { + AbstractHttpEntity entity; + if (data.length < getMinGzipSize(resolver)) { + entity = new ByteArrayEntity(data); + } else { + ByteArrayOutputStream arr = new ByteArrayOutputStream(); + OutputStream zipper = new GZIPOutputStream(arr); + zipper.write(data); + zipper.close(); + entity = new ByteArrayEntity(arr.toByteArray()); + entity.setContentEncoding("gzip"); + } + return entity; + } + + /** + * Retrieves the minimum size for compressing data. + * Shorter data will not be compressed. + */ + public static long getMinGzipSize(ContentResolver resolver) { + return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant. + } + + /* cURL logging support. */ + + /** + * Logging tag and level. + */ + private static class LoggingConfiguration { + + private final String tag; + private final int level; + + private LoggingConfiguration(String tag, int level) { + this.tag = tag; + this.level = level; + } + + /** + * Returns true if logging is turned on for this configuration. + */ + private boolean isLoggable() { + return Log.isLoggable(tag, level); + } + + /** + * Prints a message using this configuration. + */ + private void println(String message) { + Log.println(level, tag, message); + } + } + + /** cURL logging configuration. */ + private volatile LoggingConfiguration curlConfiguration; + + /** + * Enables cURL request logging for this client. + * + * @param name to log messages with + * @param level at which to log messages (see {@link android.util.Log}) + */ + public void enableCurlLogging(String name, int level) { + if (name == null) { + throw new NullPointerException("name"); + } + if (level < Log.VERBOSE || level > Log.ASSERT) { + throw new IllegalArgumentException("Level is out of range [" + + Log.VERBOSE + ".." + Log.ASSERT + "]"); + } + + curlConfiguration = new LoggingConfiguration(name, level); + } + + /** + * Disables cURL logging for this client. + */ + public void disableCurlLogging() { + curlConfiguration = null; + } + + /** + * Logs cURL commands equivalent to requests. + */ + private class CurlLogger implements HttpRequestInterceptor { + public void process(HttpRequest request, HttpContext context) + throws HttpException, IOException { + LoggingConfiguration configuration = curlConfiguration; + if (configuration != null + && configuration.isLoggable() + && request instanceof HttpUriRequest) { + // Never print auth token -- we used to check ro.secure=0 to + // enable that, but can't do that in unbundled code. + configuration.println(toCurl((HttpUriRequest) request, false)); + } + } + } + + /** + * Generates a cURL command equivalent to the given request. + */ + private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException { + StringBuilder builder = new StringBuilder(); + + builder.append("curl "); + + for (Header header: request.getAllHeaders()) { + if (!logAuthToken + && (header.getName().equals("Authorization") || + header.getName().equals("Cookie"))) { + continue; + } + builder.append("--header \""); + builder.append(header.toString().trim()); + builder.append("\" "); + } + + URI uri = request.getURI(); + + // If this is a wrapped request, use the URI from the original + // request instead. getURI() on the wrapper seems to return a + // relative URI. We want an absolute URI. + if (request instanceof RequestWrapper) { + HttpRequest original = ((RequestWrapper) request).getOriginal(); + if (original instanceof HttpUriRequest) { + uri = ((HttpUriRequest) original).getURI(); + } + } + + builder.append("\""); + builder.append(uri); + builder.append("\""); + + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntityEnclosingRequest entityRequest = + (HttpEntityEnclosingRequest) request; + HttpEntity entity = entityRequest.getEntity(); + if (entity != null && entity.isRepeatable()) { + if (entity.getContentLength() < 1024) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + entity.writeTo(stream); + String entityString = stream.toString(); + + // TODO: Check the content type, too. + builder.append(" --data-ascii \"") + .append(entityString) + .append("\""); + } else { + builder.append(" [TOO MUCH DATA TO INCLUDE]"); + } + } + } + + return builder.toString(); + } +} diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java index e1327dd..c527fe4 100644 --- a/core/java/android/net/http/CertificateChainValidator.java +++ b/core/java/android/net/http/CertificateChainValidator.java @@ -16,7 +16,8 @@ package android.net.http; -import com.android.common.DomainNameValidator; + +import com.android.internal.net.DomainNameValidator; import org.apache.harmony.xnet.provider.jsse.SSLParameters; diff --git a/core/java/android/net/http/HttpDateTime.java b/core/java/android/net/http/HttpDateTime.java new file mode 100644 index 0000000..c7a31ee --- /dev/null +++ b/core/java/android/net/http/HttpDateTime.java @@ -0,0 +1,225 @@ +/* + * 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.net.http; + +import android.text.format.Time; + +import java.util.Calendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Helper for parsing an HTTP date. + */ +public final class HttpDateTime { + + /* + * Regular expression for parsing HTTP-date. + * + * Wdy, DD Mon YYYY HH:MM:SS GMT + * RFC 822, updated by RFC 1123 + * + * Weekday, DD-Mon-YY HH:MM:SS GMT + * RFC 850, obsoleted by RFC 1036 + * + * Wdy Mon DD HH:MM:SS YYYY + * ANSI C's asctime() format + * + * with following variations + * + * Wdy, DD-Mon-YYYY HH:MM:SS GMT + * Wdy, (SP)D Mon YYYY HH:MM:SS GMT + * Wdy,DD Mon YYYY HH:MM:SS GMT + * Wdy, DD-Mon-YY HH:MM:SS GMT + * Wdy, DD Mon YYYY HH:MM:SS -HHMM + * Wdy, DD Mon YYYY HH:MM:SS + * Wdy Mon (SP)D HH:MM:SS YYYY + * Wdy Mon DD HH:MM:SS YYYY GMT + * + * HH can be H if the first digit is zero. + * + * Mon can be the full name of the month. + */ + private static final String HTTP_DATE_RFC_REGEXP = + "([0-9]{1,2})[- ]([A-Za-z]{3,9})[- ]([0-9]{2,4})[ ]" + + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])"; + + private static final String HTTP_DATE_ANSIC_REGEXP = + "[ ]([A-Za-z]{3,9})[ ]+([0-9]{1,2})[ ]" + + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})"; + + /** + * The compiled version of the HTTP-date regular expressions. + */ + private static final Pattern HTTP_DATE_RFC_PATTERN = + Pattern.compile(HTTP_DATE_RFC_REGEXP); + private static final Pattern HTTP_DATE_ANSIC_PATTERN = + Pattern.compile(HTTP_DATE_ANSIC_REGEXP); + + private static class TimeOfDay { + TimeOfDay(int h, int m, int s) { + this.hour = h; + this.minute = m; + this.second = s; + } + + int hour; + int minute; + int second; + } + + public static Long parse(String timeString) + throws IllegalArgumentException { + + int date = 1; + int month = Calendar.JANUARY; + int year = 1970; + TimeOfDay timeOfDay; + + Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString); + if (rfcMatcher.find()) { + date = getDate(rfcMatcher.group(1)); + month = getMonth(rfcMatcher.group(2)); + year = getYear(rfcMatcher.group(3)); + timeOfDay = getTime(rfcMatcher.group(4)); + } else { + Matcher ansicMatcher = HTTP_DATE_ANSIC_PATTERN.matcher(timeString); + if (ansicMatcher.find()) { + month = getMonth(ansicMatcher.group(1)); + date = getDate(ansicMatcher.group(2)); + timeOfDay = getTime(ansicMatcher.group(3)); + year = getYear(ansicMatcher.group(4)); + } else { + throw new IllegalArgumentException(); + } + } + + // FIXME: Y2038 BUG! + if (year >= 2038) { + year = 2038; + month = Calendar.JANUARY; + date = 1; + } + + Time time = new Time(Time.TIMEZONE_UTC); + time.set(timeOfDay.second, timeOfDay.minute, timeOfDay.hour, date, + month, year); + return time.toMillis(false /* use isDst */); + } + + private static int getDate(String dateString) { + if (dateString.length() == 2) { + return (dateString.charAt(0) - '0') * 10 + + (dateString.charAt(1) - '0'); + } else { + return (dateString.charAt(0) - '0'); + } + } + + /* + * jan = 9 + 0 + 13 = 22 + * feb = 5 + 4 + 1 = 10 + * mar = 12 + 0 + 17 = 29 + * apr = 0 + 15 + 17 = 32 + * may = 12 + 0 + 24 = 36 + * jun = 9 + 20 + 13 = 42 + * jul = 9 + 20 + 11 = 40 + * aug = 0 + 20 + 6 = 26 + * sep = 18 + 4 + 15 = 37 + * oct = 14 + 2 + 19 = 35 + * nov = 13 + 14 + 21 = 48 + * dec = 3 + 4 + 2 = 9 + */ + private static int getMonth(String monthString) { + int hash = Character.toLowerCase(monthString.charAt(0)) + + Character.toLowerCase(monthString.charAt(1)) + + Character.toLowerCase(monthString.charAt(2)) - 3 * 'a'; + switch (hash) { + case 22: + return Calendar.JANUARY; + case 10: + return Calendar.FEBRUARY; + case 29: + return Calendar.MARCH; + case 32: + return Calendar.APRIL; + case 36: + return Calendar.MAY; + case 42: + return Calendar.JUNE; + case 40: + return Calendar.JULY; + case 26: + return Calendar.AUGUST; + case 37: + return Calendar.SEPTEMBER; + case 35: + return Calendar.OCTOBER; + case 48: + return Calendar.NOVEMBER; + case 9: + return Calendar.DECEMBER; + default: + throw new IllegalArgumentException(); + } + } + + private static int getYear(String yearString) { + if (yearString.length() == 2) { + int year = (yearString.charAt(0) - '0') * 10 + + (yearString.charAt(1) - '0'); + if (year >= 70) { + return year + 1900; + } else { + return year + 2000; + } + } else if (yearString.length() == 3) { + // According to RFC 2822, three digit years should be added to 1900. + int year = (yearString.charAt(0) - '0') * 100 + + (yearString.charAt(1) - '0') * 10 + + (yearString.charAt(2) - '0'); + return year + 1900; + } else if (yearString.length() == 4) { + return (yearString.charAt(0) - '0') * 1000 + + (yearString.charAt(1) - '0') * 100 + + (yearString.charAt(2) - '0') * 10 + + (yearString.charAt(3) - '0'); + } else { + return 1970; + } + } + + private static TimeOfDay getTime(String timeString) { + // HH might be H + int i = 0; + int hour = timeString.charAt(i++) - '0'; + if (timeString.charAt(i) != ':') + hour = hour * 10 + (timeString.charAt(i++) - '0'); + // Skip ':' + i++; + + int minute = (timeString.charAt(i++) - '0') * 10 + + (timeString.charAt(i++) - '0'); + // Skip ':' + i++; + + int second = (timeString.charAt(i++) - '0') * 10 + + (timeString.charAt(i++) - '0'); + + return new TimeOfDay(hour, minute, second); + } +} diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index adeef54..d965962 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -29,8 +29,8 @@ import android.telephony.SmsMessage; import android.text.TextUtils; import android.util.Config; import android.util.Log; +import android.util.Patterns; -import com.android.common.Patterns; import java.util.HashSet; import java.util.Set; diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index 7c15cec..bf411e1 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -32,6 +32,15 @@ import android.os.Bundle; * Constants for supporting speech recognition through starting an {@link Intent} */ public class RecognizerIntent { + /** + * The extra key used in an intent to the speech recognizer for voice search. Not + * generally to be used by developers. The system search dialog uses this, for example, + * to set a calling package for identification by a voice search API. If this extra + * is set by anyone but the system process, it should be overridden by the voice search + * implementation. + */ + public final static String EXTRA_CALLING_PACKAGE = "calling_package"; + private RecognizerIntent() { // Not for instantiating. } diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java index 862305b..04730ec 100644 --- a/core/java/android/text/AutoText.java +++ b/core/java/android/text/AutoText.java @@ -18,7 +18,9 @@ package android.text; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; + import android.view.View; import org.xmlpull.v1.XmlPullParser; diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index 33ecc01..07e71f9 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -46,7 +46,8 @@ import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import android.util.Log; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; import java.io.IOException; import java.io.StringReader; diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index 7f87365..9860588 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -22,10 +22,10 @@ import android.text.style.URLSpan; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; +import android.util.Patterns; import android.webkit.WebView; import android.widget.TextView; -import com.android.common.Patterns; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java new file mode 100644 index 0000000..2ee6e8a --- /dev/null +++ b/core/java/android/util/Patterns.java @@ -0,0 +1,232 @@ +/* + * 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.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Commonly used regular expression patterns. + */ +public class Patterns { + /** + * Regular expression to match all IANA top-level domains. + * List accurate as of 2010/02/05. List taken from: + * http://data.iana.org/TLD/tlds-alpha-by-domain.txt + * This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py + */ + public static final String TOP_LEVEL_DOMAIN_STR = + "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])" + + "|(biz|b[abdefghijmnorstvwyz])" + + "|(cat|com|coop|c[acdfghiklmnoruvxyz])" + + "|d[ejkmoz]" + + "|(edu|e[cegrstu])" + + "|f[ijkmor]" + + "|(gov|g[abdefghilmnpqrstuwy])" + + "|h[kmnrtu]" + + "|(info|int|i[delmnoqrst])" + + "|(jobs|j[emop])" + + "|k[eghimnprwyz]" + + "|l[abcikrstuvy]" + + "|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])" + + "|(name|net|n[acefgilopruz])" + + "|(org|om)" + + "|(pro|p[aefghklmnrstwy])" + + "|qa" + + "|r[eosuw]" + + "|s[abcdeghijklmnortuvyz]" + + "|(tel|travel|t[cdfghjklmnoprtvwz])" + + "|u[agksyz]" + + "|v[aceginu]" + + "|w[fs]" + + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)" + + "|y[etu]" + + "|z[amw])"; + + /** + * Regular expression pattern to match all IANA top-level domains. + */ + public static final Pattern TOP_LEVEL_DOMAIN = + Pattern.compile(TOP_LEVEL_DOMAIN_STR); + + /** + * Regular expression to match all IANA top-level domains for WEB_URL. + * List accurate as of 2010/02/05. List taken from: + * http://data.iana.org/TLD/tlds-alpha-by-domain.txt + * This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py + */ + public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = + "(?:" + + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])" + + "|(?:biz|b[abdefghijmnorstvwyz])" + + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])" + + "|d[ejkmoz]" + + "|(?:edu|e[cegrstu])" + + "|f[ijkmor]" + + "|(?:gov|g[abdefghilmnpqrstuwy])" + + "|h[kmnrtu]" + + "|(?:info|int|i[delmnoqrst])" + + "|(?:jobs|j[emop])" + + "|k[eghimnprwyz]" + + "|l[abcikrstuvy]" + + "|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])" + + "|(?:name|net|n[acefgilopruz])" + + "|(?:org|om)" + + "|(?:pro|p[aefghklmnrstwy])" + + "|qa" + + "|r[eosuw]" + + "|s[abcdeghijklmnortuvyz]" + + "|(?:tel|travel|t[cdfghjklmnoprtvwz])" + + "|u[agksyz]" + + "|v[aceginu]" + + "|w[fs]" + + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)" + + "|y[etu]" + + "|z[amw]))"; + + /** + * Good characters for Internationalized Resource Identifiers (IRI). + * This comprises most common used Unicode characters allowed in IRI + * as detailed in RFC 3987. + * Specifically, those two byte Unicode characters are not included. + */ + public static final String GOOD_IRI_CHAR = + "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; + + /** + * Regular expression pattern to match most part of RFC 3987 + * Internationalized URLs, aka IRIs. Commonly used Unicode characters are + * added. + */ + public static final Pattern WEB_URL = Pattern.compile( + "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" + + "((?:(?:[" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]{0,64}\\.)+" // named host + + TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL + + "|(?:(?:25[0-5]|2[0-4]" // or ip address + + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]" + + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]" + + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + + "|[1-9][0-9]|[0-9])))" + + "(?:\\:\\d{1,5})?)" // plus option port number + + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params + + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" + + "(?:\\b|$)"); // and finally, a word boundary or end of + // input. This is to stop foo.sure from + // matching as foo.su + + public static final Pattern IP_ADDRESS + = Pattern.compile( + "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + + "|[1-9][0-9]|[0-9]))"); + + public static final Pattern DOMAIN_NAME + = Pattern.compile( + "(((([" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]*)*[" + GOOD_IRI_CHAR + "]\\.)+" + + TOP_LEVEL_DOMAIN + ")|" + + IP_ADDRESS + ")"); + + public static final Pattern EMAIL_ADDRESS + = Pattern.compile( + "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" + + "\\@" + + "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" + + "(" + + "\\." + + "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" + + ")+" + ); + + /** + * This pattern is intended for searching for things that look like they + * might be phone numbers in arbitrary text, not for validating whether + * something is in fact a phone number. It will miss many things that + * are legitimate phone numbers. + * + * <p> The pattern matches the following: + * <ul> + * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes + * may follow. + * <li>Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes. + * <li>A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes. + * </ul> + */ + public static final Pattern PHONE + = Pattern.compile( // sdd = space, dot, or dash + "(\\+[0-9]+[\\- \\.]*)?" // +<digits><sdd>* + + "(\\([0-9]+\\)[\\- \\.]*)?" // (<digits>)<sdd>* + + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> + + /** + * Convenience method to take all of the non-null matching groups in a + * regex Matcher and return them as a concatenated string. + * + * @param matcher The Matcher object from which grouped text will + * be extracted + * + * @return A String comprising all of the non-null matched + * groups concatenated together + */ + public static final String concatGroups(Matcher matcher) { + StringBuilder b = new StringBuilder(); + final int numGroups = matcher.groupCount(); + + for (int i = 1; i <= numGroups; i++) { + String s = matcher.group(i); + + System.err.println("Group(" + i + ") : " + s); + + if (s != null) { + b.append(s); + } + } + + return b.toString(); + } + + /** + * Convenience method to return only the digits and plus signs + * in the matching string. + * + * @param matcher The Matcher object from which digits and plus will + * be extracted + * + * @return A String comprising all of the digits and plus in + * the match + */ + public static final String digitsAndPlusOnly(Matcher matcher) { + StringBuilder buffer = new StringBuilder(); + String matchingRegion = matcher.group(); + + for (int i = 0, size = matchingRegion.length(); i < size; i++) { + char character = matchingRegion.charAt(i); + + if (character == '+' || Character.isDigit(character)) { + buffer.append(character); + } + } + return buffer.toString(); + } + + /** + * Do not create this static utility class. + */ + private Patterns() {} +} diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 4f496d7..0fc70d5 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -27,7 +27,7 @@ import java.io.IOException; import java.util.TimeZone; import java.util.Date; -import com.android.common.XmlUtils; +import com.android.internal.util.XmlUtils; /** * A class containing utility methods related to time zones. diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java index 8f855cd..ecedbe1 100644 --- a/core/java/android/util/XmlPullAttributes.java +++ b/core/java/android/util/XmlPullAttributes.java @@ -19,7 +19,8 @@ package android.util; import org.xmlpull.v1.XmlPullParser; import android.util.AttributeSet; -import com.android.common.XmlUtils; + +import com.android.internal.util.XmlUtils; /** * Provides an implementation of AttributeSet on top of an XmlPullParser. diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index 87cab3c..647556b 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -18,6 +18,7 @@ package android.webkit; import android.content.Context; import android.net.http.Headers; +import android.net.http.HttpDateTime; import android.os.FileUtils; import android.util.Log; import java.io.File; @@ -30,7 +31,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Map; -import com.android.common.HttpDateTime; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 84e34bc..1d28731 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -18,9 +18,9 @@ package android.webkit; import android.net.ParseException; import android.net.WebAddress; +import android.net.http.HttpDateTime; import android.util.Log; -import com.android.common.HttpDateTime; import java.util.ArrayList; import java.util.Arrays; |