diff options
Diffstat (limited to 'core/java/android')
56 files changed, 364 insertions, 687 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d4056c9..4268fa6 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -92,8 +92,7 @@ import com.android.internal.os.BinderInternal; import com.android.internal.os.RuntimeInit; import com.android.internal.os.SamplingProfilerIntegration; import com.android.internal.util.Objects; - -import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; +import com.android.org.conscrypt.OpenSSLSocketImpl; import java.io.File; import java.io.FileDescriptor; diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 10ea109..72c9156 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1169,7 +1169,7 @@ final class FragmentManagerImpl extends FragmentManager { if (!fragment.mHidden) { fragment.mHidden = true; if (fragment.mView != null) { - Animator anim = loadAnimator(fragment, transition, true, + Animator anim = loadAnimator(fragment, transition, false, transitionStyle); if (anim != null) { anim.setTarget(fragment.mView); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 25c790f..bdd0adb 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -207,8 +207,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should start * the activity. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intent Intent of the activity to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, @@ -239,8 +238,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should start * the activity. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intent Intent of the activity to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, @@ -332,8 +330,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should start * the activity. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intents Array of Intents of the activities to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, @@ -383,8 +380,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should start * the activity. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intents Array of Intents of the activities to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, @@ -454,8 +450,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should perform * the broadcast. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intent The Intent to be broadcast. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, @@ -509,8 +504,7 @@ public final class PendingIntent implements Parcelable { * * @param context The Context in which this PendingIntent should start * the service. - * @param requestCode Private request code for the sender (currently - * not used). + * @param requestCode Private request code for the sender * @param intent An Intent describing the service to be started. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index bafe67d..898cc4e 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -160,10 +160,13 @@ public abstract class AbstractThreadedSyncAdapter { if (mAutoInitialize && extras != null && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { - if (ContentResolver.getIsSyncable(account, authority) < 0) { - ContentResolver.setIsSyncable(account, authority, 1); + try { + if (ContentResolver.getIsSyncable(account, authority) < 0) { + ContentResolver.setIsSyncable(account, authority, 1); + } + } finally { + syncContextClient.onFinished(new SyncResult()); } - syncContextClient.onFinished(new SyncResult()); return; } SyncThread syncThread = new SyncThread( diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index fc95728..330b7e5 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -6979,7 +6979,7 @@ public class Intent implements Parcelable, Cloneable { return null; } - type = type.trim().toLowerCase(Locale.US); + type = type.trim().toLowerCase(Locale.ROOT); final int semicolonIndex = type.indexOf(';'); if (semicolonIndex != -1) { diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 905ae0d..6318e38 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -54,10 +54,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration /** * IMSI MNC (Mobile Network Code), corresponding to * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a> - * resource qualifier. 0 if undefined. + * resource qualifier. 0 if undefined. Note that the actual MNC may be 0; in order to check + * for this use the {@link #MNC_ZERO} symbol. */ public int mnc; - + + /** + * Constant used to to represent MNC (Mobile Network Code) zero. + * 0 cannot be used, since it is used to represent an undefined MNC. + */ + public static final int MNC_ZERO = 0xffff; + /** * Current user preference for the locale, corresponding to * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a> @@ -853,11 +860,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_SCREEN_SIZE; screenHeightDp = delta.screenHeightDp; } - if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { - changed |= ActivityInfo.CONFIG_SCREEN_SIZE; + if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED + && smallestScreenWidthDp != delta.smallestScreenWidthDp) { + changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; smallestScreenWidthDp = delta.smallestScreenWidthDp; } - if (delta.densityDpi != DENSITY_DPI_UNDEFINED) { + if (delta.densityDpi != DENSITY_DPI_UNDEFINED && + densityDpi != delta.densityDpi) { changed |= ActivityInfo.CONFIG_DENSITY; densityDpi = delta.densityDpi; } diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 1fc1226..c125544 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -792,6 +792,18 @@ public class DatabaseUtils { } /** + * Query the table to check whether a table is empty or not + * @param db the database the table is in + * @param table the name of the table to query + * @return True if the table is empty + * @hide + */ + public static boolean queryIsEmpty(SQLiteDatabase db, String table) { + long isEmpty = longForQuery(db, "select exists(select 1 from " + table + ")", null); + return isEmpty == 0; + } + + /** * Utility method to run the query on the db and return the value in the * first column of the first row. */ @@ -1364,7 +1376,7 @@ public class DatabaseUtils { if (sql.length() < 3) { return STATEMENT_OTHER; } - String prefixSql = sql.substring(0, 3).toUpperCase(Locale.US); + String prefixSql = sql.substring(0, 3).toUpperCase(Locale.ROOT); if (prefixSql.equals("SEL")) { return STATEMENT_SELECT; } else if (prefixSql.equals("INS") || diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java index a9e39c3..b234e34 100644..100755 --- a/core/java/android/database/DefaultDatabaseErrorHandler.java +++ b/core/java/android/database/DefaultDatabaseErrorHandler.java @@ -99,7 +99,7 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { } Log.e(TAG, "deleting the database file: " + fileName); try { - new File(fileName).delete(); + SQLiteDatabase.deleteDatabase(new File(fileName)); } catch (Exception e) { /* print warning and ignore exception */ Log.w(TAG, "delete failed: " + e.getMessage()); diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 4f59e8e..725a1ff 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -30,9 +30,9 @@ import android.util.Log; import android.util.LruCache; import android.util.Printer; -import java.sql.Date; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Map; import java.util.regex.Pattern; diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index 842a482..220b40d 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -97,7 +97,9 @@ public class DdmHandleHello extends ChunkHandler { } /* - * Handle introductory packet. + * Handle introductory packet. This is called during JNI_CreateJavaVM + * before frameworks native methods are registered, so be careful not + * to call any APIs that depend on frameworks native code. */ private Chunk handleHELO(Chunk request) { if (false) diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 2b15afd..4881d14 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -431,7 +431,7 @@ public class InputMethodService extends AbstractInputMethodService { } } // If user uses hard keyboard, IME button should always be shown. - boolean showing = onEvaluateInputViewShown(); + boolean showing = isInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition); if (resultReceiver != null) { diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index ac2b0d9..7999c66 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -178,6 +178,7 @@ public class EthernetDataTracker implements NetworkStateTracker { } mLinkProperties = dhcpResults.linkProperties; + mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); msg.sendToTarget(); diff --git a/core/java/android/net/MailTo.java b/core/java/android/net/MailTo.java index ca28f86..b90dcb1 100644 --- a/core/java/android/net/MailTo.java +++ b/core/java/android/net/MailTo.java @@ -17,6 +17,7 @@ package android.net; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -84,7 +85,7 @@ public class MailTo { } // insert the headers with the name in lowercase so that // we can easily find common headers - m.mHeaders.put(Uri.decode(nameval[0]).toLowerCase(), + m.mHeaders.put(Uri.decode(nameval[0]).toLowerCase(Locale.ROOT), nameval.length > 1 ? Uri.decode(nameval[1]) : null); } } diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java index 3cc0bc5..5d95f41 100644 --- a/core/java/android/net/NetworkConfig.java +++ b/core/java/android/net/NetworkConfig.java @@ -17,6 +17,7 @@ package android.net; import android.util.Log; +import java.util.Locale; /** * Describes the buildtime configuration of a network. @@ -63,7 +64,7 @@ public class NetworkConfig { */ public NetworkConfig(String init) { String fragments[] = init.split(","); - name = fragments[0].trim().toLowerCase(); + name = fragments[0].trim().toLowerCase(Locale.ROOT); type = Integer.parseInt(fragments[1]); radio = Integer.parseInt(fragments[2]); priority = Integer.parseInt(fragments[3]); diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index cd799da..9c4772b 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -25,6 +25,7 @@ import android.util.Log; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.util.Locale; /** * A container class for the http proxy info @@ -87,7 +88,7 @@ public class ProxyProperties implements Parcelable { if (mExclusionList == null) { mParsedExclusionList = new String[0]; } else { - String splitExclusionList[] = exclusionList.toLowerCase().split(","); + String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(","); mParsedExclusionList = new String[splitExclusionList.length * 2]; for (int i = 0; i < splitExclusionList.length; i++) { String s = splitExclusionList[i].trim(); diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 0fe5cc4..208b212 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -18,6 +18,9 @@ package android.net; import android.os.SystemProperties; import android.util.Log; +import com.android.org.conscrypt.OpenSSLContextImpl; +import com.android.org.conscrypt.OpenSSLSocketImpl; +import com.android.org.conscrypt.SSLClientSessionCache; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; @@ -36,9 +39,6 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl; -import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; /** * SSLSocketFactory implementation with several extra features: @@ -86,6 +86,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { private TrustManager[] mTrustManagers = null; private KeyManager[] mKeyManagers = null; private byte[] mNpnProtocols = null; + private byte[] mAlpnProtocols = null; private PrivateKey mChannelIdPrivateKey = null; private final int mHandshakeTimeoutMillis; @@ -265,19 +266,42 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * must be non-empty and of length less than 256. */ public void setNpnProtocols(byte[][] npnProtocols) { - this.mNpnProtocols = toNpnProtocolsList(npnProtocols); + this.mNpnProtocols = toLengthPrefixedList(npnProtocols); + } + + /** + * Sets the + * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01"> + * Application Layer Protocol Negotiation (ALPN)</a> protocols that this peer + * is interested in. + * + * <p>For servers this is the sequence of protocols to advertise as + * supported, in order of preference. This list is sent unencrypted to + * all clients that support ALPN. + * + * <p>For clients this is a list of supported protocols to match against the + * server's list. If there is no protocol supported by both client and + * server then the first protocol in the client's list will be selected. + * The order of the client's protocols is otherwise insignificant. + * + * @param protocols a non-empty list of protocol byte arrays. All arrays + * must be non-empty and of length less than 256. + * @hide + */ + public void setAlpnProtocols(byte[][] protocols) { + this.mAlpnProtocols = toLengthPrefixedList(protocols); } /** * Returns an array containing the concatenation of length-prefixed byte * strings. */ - static byte[] toNpnProtocolsList(byte[]... npnProtocols) { - if (npnProtocols.length == 0) { - throw new IllegalArgumentException("npnProtocols.length == 0"); + static byte[] toLengthPrefixedList(byte[]... items) { + if (items.length == 0) { + throw new IllegalArgumentException("items.length == 0"); } int totalLength = 0; - for (byte[] s : npnProtocols) { + for (byte[] s : items) { if (s.length == 0 || s.length > 255) { throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length); } @@ -285,7 +309,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } byte[] result = new byte[totalLength]; int pos = 0; - for (byte[] s : npnProtocols) { + for (byte[] s : items) { result[pos++] = (byte) s.length; for (byte b : s) { result[pos++] = b; @@ -307,6 +331,20 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } /** + * Returns the + * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01">Application + * Layer Protocol Negotiation (ALPN)</a> protocol selected by client and server, or null + * if no protocol was negotiated. + * + * @param socket a socket created by this factory. + * @throws IllegalArgumentException if the socket was not created by this factory. + * @hide + */ + public byte[] getAlpnSelectedProtocol(Socket socket) { + return castToOpenSSLSocket(socket).getAlpnSelectedProtocol(); + } + + /** * Sets the {@link KeyManager}s to be used for connections made by this factory. */ public void setKeyManagers(KeyManager[] keyManagers) { @@ -390,6 +428,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); if (mSecure) { @@ -410,6 +449,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { public Socket createSocket() throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); return s; @@ -428,6 +468,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( addr, port, localAddr, localPort); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); return s; @@ -444,6 +485,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { public Socket createSocket(InetAddress addr, int port) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); return s; @@ -461,6 +503,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( host, port, localAddr, localPort); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); if (mSecure) { @@ -479,6 +522,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { public Socket createSocket(String host, int port) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port); s.setNpnProtocols(mNpnProtocols); + s.setAlpnProtocols(mAlpnProtocols); s.setHandshakeTimeout(mHandshakeTimeoutMillis); s.setChannelIdPrivateKey(mChannelIdPrivateKey); if (mSecure) { diff --git a/core/java/android/net/SSLSessionCache.java b/core/java/android/net/SSLSessionCache.java index 4cbeb94..15421de 100644 --- a/core/java/android/net/SSLSessionCache.java +++ b/core/java/android/net/SSLSessionCache.java @@ -16,12 +16,12 @@ package android.net; -import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache; -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; - import android.content.Context; import android.util.Log; +import com.android.org.conscrypt.FileClientSessionCache; +import com.android.org.conscrypt.SSLClientSessionCache; + import java.io.File; import java.io.IOException; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 4b022d9..132173d 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -26,7 +26,7 @@ import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.nio.charset.Charsets; +import java.nio.charset.StandardCharsets; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; @@ -1689,7 +1689,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { return ""; } else { String encodedValue = query.substring(separator + 1, end); - return UriCodec.decode(encodedValue, true, Charsets.UTF_8, false); + return UriCodec.decode(encodedValue, true, StandardCharsets.UTF_8, false); } } @@ -1717,7 +1717,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { if (flag == null) { return defaultValue; } - flag = flag.toLowerCase(); + flag = flag.toLowerCase(Locale.ROOT); return (!"false".equals(flag) && !"0".equals(flag)); } @@ -1745,7 +1745,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public Uri normalizeScheme() { String scheme = getScheme(); if (scheme == null) return this; // give up - String lowerScheme = scheme.toLowerCase(Locale.US); + String lowerScheme = scheme.toLowerCase(Locale.ROOT); if (scheme.equals(lowerScheme)) return this; // no change return buildUpon().scheme(lowerScheme).build(); @@ -1928,7 +1928,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { if (s == null) { return null; } - return UriCodec.decode(s, false, Charsets.UTF_8, false); + return UriCodec.decode(s, false, StandardCharsets.UTF_8, false); } /** diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java index a6efcdd..d2073b4 100644 --- a/core/java/android/net/UrlQuerySanitizer.java +++ b/core/java/android/net/UrlQuerySanitizer.java @@ -19,6 +19,7 @@ package android.net; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.StringTokenizer; @@ -305,7 +306,7 @@ public class UrlQuerySanitizer { int length = value.length(); if ((mFlags & SCRIPT_URL_OK) != 0) { if (length >= MIN_SCRIPT_PREFIX_LENGTH) { - String asLower = value.toLowerCase(); + String asLower = value.toLowerCase(Locale.ROOT); if (asLower.startsWith(JAVASCRIPT_PREFIX) || asLower.startsWith(VBSCRIPT_PREFIX)) { return ""; diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java index 052f921..8126b75 100644 --- a/core/java/android/net/WebAddress.java +++ b/core/java/android/net/WebAddress.java @@ -18,6 +18,7 @@ package android.net; import static android.util.Patterns.GOOD_IRI_CHAR; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -77,7 +78,7 @@ public class WebAddress { String t; if (m.matches()) { t = m.group(MATCH_GROUP_SCHEME); - if (t != null) mScheme = t.toLowerCase(); + if (t != null) mScheme = t.toLowerCase(Locale.ROOT); t = m.group(MATCH_GROUP_AUTHORITY); if (t != null) mAuthInfo = t; t = m.group(MATCH_GROUP_HOST); diff --git a/core/java/android/net/dhcp/DhcpPacket.java b/core/java/android/net/dhcp/DhcpPacket.java index 7d2bd69..317a9b4 100644 --- a/core/java/android/net/dhcp/DhcpPacket.java +++ b/core/java/android/net/dhcp/DhcpPacket.java @@ -7,7 +7,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.charset.Charsets; +import java.nio.charset.StandardCharsets; import java.nio.ShortBuffer; import java.util.ArrayList; @@ -540,7 +540,7 @@ abstract class DhcpPacket { private static String readAsciiString(ByteBuffer buf, int byteCount) { byte[] bytes = new byte[byteCount]; buf.get(bytes); - return new String(bytes, 0, bytes.length, Charsets.US_ASCII); + return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII); } /** diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java index f66075d..3652a4c 100644 --- a/core/java/android/net/http/CertificateChainValidator.java +++ b/core/java/android/net/http/CertificateChainValidator.java @@ -16,21 +16,22 @@ package android.net.http; +import com.android.org.conscrypt.SSLParametersImpl; +import com.android.org.conscrypt.TrustManagerImpl; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.net.ssl.DefaultHostnameVerifier; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.X509TrustManager; -import org.apache.harmony.security.provider.cert.X509CertImpl; -import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl; -import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl; /** * Class responsible for all server certificate validation functionality @@ -118,8 +119,14 @@ public class CertificateChainValidator { X509Certificate[] serverCertificates = new X509Certificate[certChain.length]; - for (int i = 0; i < certChain.length; ++i) { - serverCertificates[i] = new X509CertImpl(certChain[i]); + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + for (int i = 0; i < certChain.length; ++i) { + serverCertificates[i] = (X509Certificate) cf.generateCertificate( + new ByteArrayInputStream(certChain[i])); + } + } catch (CertificateException e) { + throw new IOException("can't read certificate", e); } return verifyServerDomainAndCertificates(serverCertificates, domain, authType); diff --git a/core/java/android/net/http/HttpAuthHeader.java b/core/java/android/net/http/HttpAuthHeader.java index d41284c..3abac23 100644 --- a/core/java/android/net/http/HttpAuthHeader.java +++ b/core/java/android/net/http/HttpAuthHeader.java @@ -16,6 +16,8 @@ package android.net.http; +import java.util.Locale; + /** * HttpAuthHeader: a class to store HTTP authentication-header parameters. * For more information, see: RFC 2617: HTTP Authentication. @@ -380,12 +382,12 @@ public class HttpAuthHeader { } if (token.equalsIgnoreCase(QOP_TOKEN)) { - mQop = value.toLowerCase(); + mQop = value.toLowerCase(Locale.ROOT); return; } if (token.equalsIgnoreCase(ALGORITHM_TOKEN)) { - mAlgorithm = value.toLowerCase(); + mAlgorithm = value.toLowerCase(Locale.ROOT); return; } } diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java index 73f3d7c..269dfb8 100644 --- a/core/java/android/net/http/HttpResponseCache.java +++ b/core/java/android/net/http/HttpResponseCache.java @@ -17,21 +17,21 @@ package android.net.http; import android.content.Context; +import com.android.okhttp.OkResponseCache; +import com.android.okhttp.ResponseSource; +import com.android.okhttp.internal.DiskLruCache; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.net.CacheRequest; import java.net.CacheResponse; -import java.net.ExtendedResponseCache; import java.net.HttpURLConnection; import java.net.ResponseCache; -import java.net.ResponseSource; import java.net.URI; import java.net.URLConnection; import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; -import libcore.io.DiskLruCache; import libcore.io.IoUtils; import org.apache.http.impl.client.DefaultHttpClient; @@ -151,13 +151,12 @@ import org.apache.http.impl.client.DefaultHttpClient; * } catch (Exception httpResponseCacheNotAvailable) { * }}</pre> */ -public final class HttpResponseCache extends ResponseCache - implements Closeable, ExtendedResponseCache { +public final class HttpResponseCache extends ResponseCache implements Closeable { - private final libcore.net.http.HttpResponseCache delegate; + private final com.android.okhttp.HttpResponseCache delegate; - private HttpResponseCache(File directory, long maxSize) throws IOException { - this.delegate = new libcore.net.http.HttpResponseCache(directory, maxSize); + private HttpResponseCache(com.android.okhttp.HttpResponseCache delegate) { + this.delegate = delegate; } /** @@ -166,7 +165,12 @@ public final class HttpResponseCache extends ResponseCache */ public static HttpResponseCache getInstalled() { ResponseCache installed = ResponseCache.getDefault(); - return installed instanceof HttpResponseCache ? (HttpResponseCache) installed : null; + if (installed instanceof com.android.okhttp.HttpResponseCache) { + return new HttpResponseCache( + (com.android.okhttp.HttpResponseCache) installed); + } + + return null; } /** @@ -181,22 +185,25 @@ public final class HttpResponseCache extends ResponseCache * warning. */ public static HttpResponseCache install(File directory, long maxSize) throws IOException { - HttpResponseCache installed = getInstalled(); - if (installed != null) { + ResponseCache installed = ResponseCache.getDefault(); + if (installed instanceof com.android.okhttp.HttpResponseCache) { + com.android.okhttp.HttpResponseCache installedCache = + (com.android.okhttp.HttpResponseCache) installed; // don't close and reopen if an equivalent cache is already installed - DiskLruCache installedCache = installed.delegate.getCache(); if (installedCache.getDirectory().equals(directory) - && installedCache.maxSize() == maxSize + && installedCache.getMaxSize() == maxSize && !installedCache.isClosed()) { - return installed; + return new HttpResponseCache(installedCache); } else { - IoUtils.closeQuietly(installed); + // The HttpResponseCache that owns this object is about to be replaced. + installedCache.close(); } } - HttpResponseCache result = new HttpResponseCache(directory, maxSize); - ResponseCache.setDefault(result); - return result; + com.android.okhttp.HttpResponseCache responseCache = + new com.android.okhttp.HttpResponseCache(directory, maxSize); + ResponseCache.setDefault(responseCache); + return new HttpResponseCache(responseCache); } @Override public CacheResponse get(URI uri, String requestMethod, @@ -214,7 +221,7 @@ public final class HttpResponseCache extends ResponseCache * deletion is pending. */ public long size() { - return delegate.getCache().size(); + return delegate.getSize(); } /** @@ -222,7 +229,7 @@ public final class HttpResponseCache extends ResponseCache * its data. */ public long maxSize() { - return delegate.getCache().maxSize(); + return delegate.getMaxSize(); } /** @@ -232,7 +239,7 @@ public final class HttpResponseCache extends ResponseCache */ public void flush() { try { - delegate.getCache().flush(); + delegate.flush(); } catch (IOException ignored) { } } @@ -263,39 +270,24 @@ public final class HttpResponseCache extends ResponseCache return delegate.getRequestCount(); } - /** @hide */ - @Override public void trackResponse(ResponseSource source) { - delegate.trackResponse(source); - } - - /** @hide */ - @Override public void trackConditionalCacheHit() { - delegate.trackConditionalCacheHit(); - } - - /** @hide */ - @Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) { - delegate.update(conditionalCacheHit, connection); - } - /** * Uninstalls the cache and releases any active resources. Stored contents * will remain on the filesystem. */ @Override public void close() throws IOException { - if (ResponseCache.getDefault() == this) { + if (ResponseCache.getDefault() == this.delegate) { ResponseCache.setDefault(null); } - delegate.getCache().close(); + delegate.close(); } /** * Uninstalls the cache and deletes all of its stored contents. */ public void delete() throws IOException { - if (ResponseCache.getDefault() == this) { + if (ResponseCache.getDefault() == this.delegate) { ResponseCache.setDefault(null); } - delegate.getCache().delete(); + delegate.delete(); } } diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java index 84765a5..7a12e53 100644 --- a/core/java/android/net/http/HttpsConnection.java +++ b/core/java/android/net/http/HttpsConnection.java @@ -18,9 +18,9 @@ package android.net.http; import android.content.Context; import android.util.Log; -import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache; -import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl; -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; +import com.android.org.conscrypt.FileClientSessionCache; +import com.android.org.conscrypt.OpenSSLContextImpl; +import com.android.org.conscrypt.SSLClientSessionCache; import org.apache.http.Header; import org.apache.http.HttpException; import org.apache.http.HttpHost; @@ -44,6 +44,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.security.KeyManagementException; import java.security.cert.X509Certificate; +import java.util.Locale; /** * A Connection connecting to a secure http server or tunneling through @@ -209,7 +210,7 @@ public class HttpsConnection extends Connection { // to add 'host' header unless we want proxy to answer us with a // 400 Bad Request for (Header h : req.mHttpRequest.getAllHeaders()) { - String headerName = h.getName().toLowerCase(); + String headerName = h.getName().toLowerCase(Locale.ROOT); if (headerName.startsWith("proxy") || headerName.equals("keep-alive") || headerName.equals("host")) { proxyReq.addHeader(h); diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index 64eacbc..cfe5f27 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -16,7 +16,7 @@ package android.net.http; -import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl; +import com.android.org.conscrypt.TrustManagerImpl; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java index 2d9dae9..2b58818 100644 --- a/core/java/android/nfc/NdefRecord.java +++ b/core/java/android/nfc/NdefRecord.java @@ -22,7 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; -import java.nio.charset.Charsets; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -311,7 +311,7 @@ public final class NdefRecord implements Parcelable { if (packageName.length() == 0) throw new IllegalArgumentException("packageName is empty"); return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, null, - packageName.getBytes(Charsets.UTF_8)); + packageName.getBytes(StandardCharsets.UTF_8)); } /** @@ -350,7 +350,7 @@ public final class NdefRecord implements Parcelable { break; } } - byte[] uriBytes = uriString.getBytes(Charsets.UTF_8); + byte[] uriBytes = uriString.getBytes(StandardCharsets.UTF_8); byte[] recordBytes = new byte[uriBytes.length + 1]; recordBytes[0] = prefix; System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length); @@ -422,7 +422,7 @@ public final class NdefRecord implements Parcelable { // missing '/' is allowed // MIME RFCs suggest ASCII encoding for content-type - byte[] typeBytes = mimeType.getBytes(Charsets.US_ASCII); + byte[] typeBytes = mimeType.getBytes(StandardCharsets.US_ASCII); return new NdefRecord(TNF_MIME_MEDIA, typeBytes, null, mimeData); } @@ -456,14 +456,14 @@ public final class NdefRecord implements Parcelable { if (domain == null) throw new NullPointerException("domain is null"); if (type == null) throw new NullPointerException("type is null"); - domain = domain.trim().toLowerCase(Locale.US); - type = type.trim().toLowerCase(Locale.US); + domain = domain.trim().toLowerCase(Locale.ROOT); + type = type.trim().toLowerCase(Locale.ROOT); if (domain.length() == 0) throw new IllegalArgumentException("domain is empty"); if (type.length() == 0) throw new IllegalArgumentException("type is empty"); - byte[] byteDomain = domain.getBytes(Charsets.UTF_8); - byte[] byteType = type.getBytes(Charsets.UTF_8); + byte[] byteDomain = domain.getBytes(StandardCharsets.UTF_8); + byte[] byteType = type.getBytes(StandardCharsets.UTF_8); byte[] b = new byte[byteDomain.length + 1 + byteType.length]; System.arraycopy(byteDomain, 0, b, 0, byteDomain.length); b[byteDomain.length] = ':'; @@ -643,7 +643,7 @@ public final class NdefRecord implements Parcelable { } break; case NdefRecord.TNF_MIME_MEDIA: - String mimeType = new String(mType, Charsets.US_ASCII); + String mimeType = new String(mType, StandardCharsets.US_ASCII); return Intent.normalizeMimeType(mimeType); } return null; @@ -694,14 +694,14 @@ public final class NdefRecord implements Parcelable { break; case TNF_ABSOLUTE_URI: - Uri uri = Uri.parse(new String(mType, Charsets.UTF_8)); + Uri uri = Uri.parse(new String(mType, StandardCharsets.UTF_8)); return uri.normalizeScheme(); case TNF_EXTERNAL_TYPE: if (inSmartPoster) { break; } - return Uri.parse("vnd.android.nfc://ext/" + new String(mType, Charsets.US_ASCII)); + return Uri.parse("vnd.android.nfc://ext/" + new String(mType, StandardCharsets.US_ASCII)); } return null; } @@ -723,7 +723,7 @@ public final class NdefRecord implements Parcelable { } String prefix = URI_PREFIX_MAP[prefixIndex]; String suffix = new String(Arrays.copyOfRange(mPayload, 1, mPayload.length), - Charsets.UTF_8); + StandardCharsets.UTF_8); return Uri.parse(prefix + suffix); } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 476b4ea..ebeb9f8 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -27,6 +27,8 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; +import libcore.io.Libcore; + /*package*/ class ZygoteStartFailedEx extends Exception { /** * Something prevented the zygote process startup from happening normally @@ -647,13 +649,17 @@ public class Process { * Returns the identifier of this process, which can be used with * {@link #killProcess} and {@link #sendSignal}. */ - public static final native int myPid(); + public static final int myPid() { + return Libcore.os.getpid(); + } /** * Returns the identifier of the calling thread, which be used with * {@link #setThreadPriority(int, int)}. */ - public static final native int myTid(); + public static final int myTid() { + return Libcore.os.gettid(); + } /** * Returns the identifier of this process's uid. This is the kernel uid @@ -661,7 +667,9 @@ public class Process { * app-specific sandbox. It is different from {@link #myUserHandle} in that * a uid identifies a specific app sandbox in a specific user. */ - public static final native int myUid(); + public static final int myUid() { + return Libcore.os.getuid(); + } /** * Returns this process's user handle. This is the diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java index 2314057..9e9521a 100644 --- a/core/java/android/os/StatFs.java +++ b/core/java/android/os/StatFs.java @@ -18,14 +18,14 @@ package android.os; import libcore.io.ErrnoException; import libcore.io.Libcore; -import libcore.io.StructStatFs; +import libcore.io.StructStatVfs; /** * Retrieve overall information about the space on a filesystem. This is a - * wrapper for Unix statfs(). + * wrapper for Unix statvfs(). */ public class StatFs { - private StructStatFs mStat; + private StructStatVfs mStat; /** * Construct a new StatFs for looking at the stats of the filesystem at @@ -39,9 +39,9 @@ public class StatFs { mStat = doStat(path); } - private static StructStatFs doStat(String path) { + private static StructStatVfs doStat(String path) { try { - return Libcore.os.statfs(path); + return Libcore.os.statvfs(path); } catch (ErrnoException e) { throw new IllegalArgumentException("Invalid path: " + path, e); } @@ -66,7 +66,7 @@ public class StatFs { /** * The size, in bytes, of a block on the file system. This corresponds to - * the Unix {@code statfs.f_bsize} field. + * the Unix {@code statvfs.f_bsize} field. */ public long getBlockSizeLong() { return mStat.f_bsize; @@ -82,7 +82,7 @@ public class StatFs { /** * The total number of blocks on the file system. This corresponds to the - * Unix {@code statfs.f_blocks} field. + * Unix {@code statvfs.f_blocks} field. */ public long getBlockCountLong() { return mStat.f_blocks; @@ -99,7 +99,7 @@ public class StatFs { /** * The total number of blocks that are free on the file system, including * reserved blocks (that are not available to normal applications). This - * corresponds to the Unix {@code statfs.f_bfree} field. Most applications + * corresponds to the Unix {@code statvfs.f_bfree} field. Most applications * will want to use {@link #getAvailableBlocks()} instead. */ public long getFreeBlocksLong() { @@ -125,7 +125,7 @@ public class StatFs { /** * The number of blocks that are free on the file system and available to - * applications. This corresponds to the Unix {@code statfs.f_bavail} field. + * applications. This corresponds to the Unix {@code statvfs.f_bavail} field. */ public long getAvailableBlocksLong() { return mStat.f_bavail; diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index e343e83..6c02965 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -1072,6 +1072,9 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) { // Do order comparison return mOrder - another.mOrder; + } else if (mTitle == another.mTitle) { + // If titles are null or share same object comparison + return 0; } else if (mTitle == null) { return 1; } else if (another.mTitle == null) { diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 028317f..a9ee96e 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -901,6 +901,8 @@ public abstract class PreferenceActivity extends ListActivity implements @Override protected void onDestroy() { + mHandler.removeMessages(MSG_BIND_PREFERENCES); + mHandler.removeMessages(MSG_BUILD_HEADERS); super.onDestroy(); if (mPreferenceManager != null) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 8b28e21..5e1f27e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -56,6 +56,7 @@ import com.android.internal.widget.ILockSettings; import java.net.URISyntaxException; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; /** * The Settings provider contains global system-level device preferences. @@ -2760,7 +2761,6 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY); MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER); MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE); - MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_CDMA_SUBSCRIPTION); } /** @hide */ @@ -5255,7 +5255,7 @@ public final class Settings { * @hide */ public static final String getBluetoothHeadsetPriorityKey(String address) { - return BLUETOOTH_HEADSET_PRIORITY_PREFIX + address.toUpperCase(); + return BLUETOOTH_HEADSET_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT); } /** @@ -5263,7 +5263,7 @@ public final class Settings { * @hide */ public static final String getBluetoothA2dpSinkPriorityKey(String address) { - return BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX + address.toUpperCase(); + return BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT); } /** @@ -5271,7 +5271,7 @@ public final class Settings { * @hide */ public static final String getBluetoothInputDevicePriorityKey(String address) { - return BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX + address.toUpperCase(); + return BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT); } /** @@ -5341,14 +5341,6 @@ public final class Settings { "preferred_network_mode"; /** - * The cdma subscription 0 = Subscription from RUIM, when available - * 1 = Subscription from NV - * @hide - */ - public static final String PREFERRED_CDMA_SUBSCRIPTION = - "preferred_cdma_subscription"; - - /** * Name of an application package to be debugged. */ public static final String DEBUG_APP = "debug_app"; diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java index 8a2bc7d..db5d8fd 100644 --- a/core/java/android/speech/srec/Recognizer.java +++ b/core/java/android/speech/srec/Recognizer.java @@ -145,7 +145,7 @@ public final class Recognizer { public static String getConfigDir(Locale locale) { if (locale == null) locale = Locale.US; String dir = "/system/usr/srec/config/" + - locale.toString().replace('_', '.').toLowerCase(); + locale.toString().replace('_', '.').toLowerCase(Locale.ROOT); if ((new File(dir)).isDirectory()) return dir; return null; } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index c497e35..d1f35dd 100644..100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -280,13 +280,9 @@ public class DateFormat { } } - /* - * The setting is not set; use the default. - * We use a resource string here instead of just DateFormat.SHORT - * so that we get a four-digit year instead a two-digit year. - */ - value = context.getString(R.string.numeric_date_format); - return value; + // The setting is not set; use the locale's default. + LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); + return d.shortDateFormat4; } /** @@ -313,39 +309,13 @@ public class DateFormat { * Gets the current date format stored as a char array. The array will contain * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order * specified by the user's format preference. Note that this order is - * only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) + * <i>only</i> appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) * dates will generally contain other punctuation, spaces, or words, * not just the day, month, and year, and not necessarily in the same * order returned here. */ public static char[] getDateFormatOrder(Context context) { - char[] order = new char[] {DATE, MONTH, YEAR}; - String value = getDateFormatString(context); - int index = 0; - boolean foundDate = false; - boolean foundMonth = false; - boolean foundYear = false; - - for (char c : value.toCharArray()) { - if (!foundDate && (c == DATE)) { - foundDate = true; - order[index] = DATE; - index++; - } - - if (!foundMonth && (c == MONTH || c == STANDALONE_MONTH)) { - foundMonth = true; - order[index] = MONTH; - index++; - } - - if (!foundYear && (c == YEAR)) { - foundYear = true; - order[index] = YEAR; - index++; - } - } - return order; + return ICU.getDateFormatOrder(getDateFormatString(context)); } private static String getDateFormatString(Context context) { diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 5a88cf6..cba350f 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Formatter; @@ -29,6 +30,7 @@ import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; +import libcore.icu.DateIntervalFormat; import libcore.icu.LocaleData; /** @@ -112,58 +114,11 @@ public class DateUtils public static final String WEEKDAY_FORMAT = "%A"; public static final String ABBREV_WEEKDAY_FORMAT = "%a"; - // This table is used to lookup the resource string id of a format string - // used for formatting a start and end date that fall in the same year. - // The index is constructed from a bit-wise OR of the boolean values: - // {showTime, showYear, showWeekDay}. For example, if showYear and - // showWeekDay are both true, then the index would be 3. /** @deprecated Do not use. */ - public static final int sameYearTable[] = { - com.android.internal.R.string.same_year_md1_md2, - com.android.internal.R.string.same_year_wday1_md1_wday2_md2, - com.android.internal.R.string.same_year_mdy1_mdy2, - com.android.internal.R.string.same_year_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.same_year_md1_time1_md2_time2, - com.android.internal.R.string.same_year_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.same_year_mdy1_time1_mdy2_time2, - com.android.internal.R.string.same_year_wday1_mdy1_time1_wday2_mdy2_time2, - - // Numeric date strings - com.android.internal.R.string.numeric_md1_md2, - com.android.internal.R.string.numeric_wday1_md1_wday2_md2, - com.android.internal.R.string.numeric_mdy1_mdy2, - com.android.internal.R.string.numeric_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.numeric_md1_time1_md2_time2, - com.android.internal.R.string.numeric_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.numeric_mdy1_time1_mdy2_time2, - com.android.internal.R.string.numeric_wday1_mdy1_time1_wday2_mdy2_time2, - }; - - // This table is used to lookup the resource string id of a format string - // used for formatting a start and end date that fall in the same month. - // The index is constructed from a bit-wise OR of the boolean values: - // {showTime, showYear, showWeekDay}. For example, if showYear and - // showWeekDay are both true, then the index would be 3. + public static final int[] sameYearTable = null; + /** @deprecated Do not use. */ - public static final int sameMonthTable[] = { - com.android.internal.R.string.same_month_md1_md2, - com.android.internal.R.string.same_month_wday1_md1_wday2_md2, - com.android.internal.R.string.same_month_mdy1_mdy2, - com.android.internal.R.string.same_month_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.same_month_md1_time1_md2_time2, - com.android.internal.R.string.same_month_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.same_month_mdy1_time1_mdy2_time2, - com.android.internal.R.string.same_month_wday1_mdy1_time1_wday2_mdy2_time2, - - com.android.internal.R.string.numeric_md1_md2, - com.android.internal.R.string.numeric_wday1_md1_wday2_md2, - com.android.internal.R.string.numeric_mdy1_mdy2, - com.android.internal.R.string.numeric_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.numeric_md1_time1_md2_time2, - com.android.internal.R.string.numeric_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.numeric_mdy1_time1_mdy2_time2, - com.android.internal.R.string.numeric_wday1_mdy1_time1_wday2_mdy2_time2, - }; + public static final int[] sameMonthTable = null; /** * Request the full spelled-out name. For use with the 'abbrev' parameter of @@ -727,7 +682,6 @@ public class DateUtils * <li>FORMAT_SHOW_TIME</li> * <li>FORMAT_SHOW_WEEKDAY</li> * <li>FORMAT_SHOW_YEAR</li> - * <li>FORMAT_NO_YEAR</li> * <li>FORMAT_SHOW_DATE</li> * <li>FORMAT_NO_MONTH_DAY</li> * <li>FORMAT_12HOUR</li> @@ -755,11 +709,9 @@ public class DateUtils * * <p> * If FORMAT_SHOW_YEAR is set, then the year is always shown. - * If FORMAT_NO_YEAR is set, then the year is not shown. - * If neither FORMAT_SHOW_YEAR nor FORMAT_NO_YEAR are set, then the year + * If FORMAT_SHOW_YEAR is not set, then the year * is shown only if it is different from the current year, or if the start - * and end dates fall on different years. If both are set, - * FORMAT_SHOW_YEAR takes precedence. + * and end dates fall on different years. * * <p> * Normally the date is shown unless the start and end day are the same. @@ -864,404 +816,13 @@ public class DateUtils */ public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis, long endMillis, int flags, String timeZone) { - Resources res = Resources.getSystem(); - boolean showTime = (flags & FORMAT_SHOW_TIME) != 0; - boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0; - boolean showYear = (flags & FORMAT_SHOW_YEAR) != 0; - boolean noYear = (flags & FORMAT_NO_YEAR) != 0; - boolean useUTC = (flags & FORMAT_UTC) != 0; - boolean abbrevWeekDay = (flags & (FORMAT_ABBREV_WEEKDAY | FORMAT_ABBREV_ALL)) != 0; - boolean abbrevMonth = (flags & (FORMAT_ABBREV_MONTH | FORMAT_ABBREV_ALL)) != 0; - boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0; - boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0; - - // If we're getting called with a single instant in time (from - // e.g. formatDateTime(), below), then we can skip a lot of - // computation below that'd otherwise be thrown out. - boolean isInstant = (startMillis == endMillis); - - Calendar startCalendar, endCalendar; - Time startDate = new Time(); - if (timeZone != null) { - startCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone)); - } else if (useUTC) { - startCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - } else { - startCalendar = Calendar.getInstance(); - } - startCalendar.setTimeInMillis(startMillis); - setTimeFromCalendar(startDate, startCalendar); - - Time endDate = new Time(); - int dayDistance; - if (isInstant) { - endDate = startDate; - dayDistance = 0; - } else { - if (timeZone != null) { - endCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone)); - } else if (useUTC) { - endCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - } else { - endCalendar = Calendar.getInstance(); - } - endCalendar.setTimeInMillis(endMillis); - setTimeFromCalendar(endDate, endCalendar); - - int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff); - int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff); - dayDistance = endJulianDay - startJulianDay; - } - - if (!isInstant - && (endDate.hour | endDate.minute | endDate.second) == 0 - && (!showTime || dayDistance <= 1)) { - endDate.monthDay -= 1; - endDate.normalize(true /* ignore isDst */); - } - - int startDay = startDate.monthDay; - int startMonthNum = startDate.month; - int startYear = startDate.year; - - int endDay = endDate.monthDay; - int endMonthNum = endDate.month; - int endYear = endDate.year; - - String startWeekDayString = ""; - String endWeekDayString = ""; - if (showWeekDay) { - String weekDayFormat = ""; - if (abbrevWeekDay) { - weekDayFormat = ABBREV_WEEKDAY_FORMAT; - } else { - weekDayFormat = WEEKDAY_FORMAT; - } - startWeekDayString = startDate.format(weekDayFormat); - endWeekDayString = isInstant ? startWeekDayString : endDate.format(weekDayFormat); - } - - String startTimeString = ""; - String endTimeString = ""; - if (showTime) { - String startTimeFormat = ""; - String endTimeFormat = ""; - boolean force24Hour = (flags & FORMAT_24HOUR) != 0; - boolean force12Hour = (flags & FORMAT_12HOUR) != 0; - boolean use24Hour; - if (force24Hour) { - use24Hour = true; - } else if (force12Hour) { - use24Hour = false; - } else { - use24Hour = DateFormat.is24HourFormat(context); - } - if (use24Hour) { - startTimeFormat = endTimeFormat = - res.getString(com.android.internal.R.string.hour_minute_24); - } else { - boolean abbrevTime = (flags & (FORMAT_ABBREV_TIME | FORMAT_ABBREV_ALL)) != 0; - boolean capAMPM = (flags & FORMAT_CAP_AMPM) != 0; - boolean noNoon = (flags & FORMAT_NO_NOON) != 0; - boolean capNoon = (flags & FORMAT_CAP_NOON) != 0; - boolean noMidnight = (flags & FORMAT_NO_MIDNIGHT) != 0; - boolean capMidnight = (flags & FORMAT_CAP_MIDNIGHT) != 0; - - boolean startOnTheHour = startDate.minute == 0 && startDate.second == 0; - boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0; - if (abbrevTime && startOnTheHour) { - if (capAMPM) { - startTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); - } - } else { - if (capAMPM) { - startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); - } - } - - // Don't waste time on setting endTimeFormat when - // we're dealing with an instant, where we'll never - // need the end point. (It's the same as the start - // point) - if (!isInstant) { - if (abbrevTime && endOnTheHour) { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); - } - } else { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); - } - } - - if (endDate.hour == 12 && endOnTheHour && !noNoon) { - if (capNoon) { - endTimeFormat = res.getString(com.android.internal.R.string.Noon); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.noon); - } - } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) { - if (capMidnight) { - endTimeFormat = res.getString(com.android.internal.R.string.Midnight); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.midnight); - } - } - } - - if (startDate.hour == 12 && startOnTheHour && !noNoon) { - if (capNoon) { - startTimeFormat = res.getString(com.android.internal.R.string.Noon); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.noon); - } - // Don't show the start time starting at midnight. Show - // 12am instead. - } - } - - startTimeString = startDate.format(startTimeFormat); - endTimeString = isInstant ? startTimeString : endDate.format(endTimeFormat); - } - - // Show the year if the user specified FORMAT_SHOW_YEAR or if - // the starting and end years are different from each other - // or from the current year. But don't show the year if the - // user specified FORMAT_NO_YEAR. - if (showYear) { - // No code... just a comment for clarity. Keep showYear - // on, as they enabled it with FORMAT_SHOW_YEAR. This - // takes precedence over them setting FORMAT_NO_YEAR. - } else if (noYear) { - // They explicitly didn't want a year. - showYear = false; - } else if (startYear != endYear) { - showYear = true; - } else { - // Show the year if it's not equal to the current year. - Time currentTime = new Time(); - currentTime.setToNow(); - showYear = startYear != currentTime.year; - } - - String defaultDateFormat, fullFormat, dateRange; - if (numericDate) { - defaultDateFormat = res.getString(com.android.internal.R.string.numeric_date); - } else if (showYear) { - if (abbrevMonth) { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_year); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_day_year); - } - } else { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.month_year); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.month_day_year); - } - } - } else { - if (abbrevMonth) { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_day); - } - } else { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.month); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.month_day); - } - } + String range = DateIntervalFormat.formatDateRange(startMillis, endMillis, flags, timeZone); + try { + formatter.out().append(range); + } catch (IOException impossible) { + throw new AssertionError(impossible); } - - if (showWeekDay) { - if (showTime) { - fullFormat = res.getString(com.android.internal.R.string.wday1_date1_time1_wday2_date2_time2); - } else { - fullFormat = res.getString(com.android.internal.R.string.wday1_date1_wday2_date2); - } - } else { - if (showTime) { - fullFormat = res.getString(com.android.internal.R.string.date1_time1_date2_time2); - } else { - fullFormat = res.getString(com.android.internal.R.string.date1_date2); - } - } - - if (noMonthDay && startMonthNum == endMonthNum && startYear == endYear) { - // Example: "January, 2008" - return formatter.format("%s", startDate.format(defaultDateFormat)); - } - - if (startYear != endYear || noMonthDay) { - // Different year or we are not showing the month day number. - // Example: "December 31, 2007 - January 1, 2008" - // Or: "January - February, 2008" - String startDateString = startDate.format(defaultDateFormat); - String endDateString = endDate.format(defaultDateFormat); - - // The values that are used in a fullFormat string are specified - // by position. - return formatter.format(fullFormat, - startWeekDayString, startDateString, startTimeString, - endWeekDayString, endDateString, endTimeString); - } - - // Get the month, day, and year strings for the start and end dates - String monthFormat; - if (numericDate) { - monthFormat = NUMERIC_MONTH_FORMAT; - } else if (abbrevMonth) { - monthFormat = - res.getString(com.android.internal.R.string.short_format_month); - } else { - monthFormat = MONTH_FORMAT; - } - String startMonthString = startDate.format(monthFormat); - String startMonthDayString = startDate.format(MONTH_DAY_FORMAT); - String startYearString = startDate.format(YEAR_FORMAT); - - String endMonthString = isInstant ? null : endDate.format(monthFormat); - String endMonthDayString = isInstant ? null : endDate.format(MONTH_DAY_FORMAT); - String endYearString = isInstant ? null : endDate.format(YEAR_FORMAT); - - String startStandaloneMonthString = startMonthString; - String endStandaloneMonthString = endMonthString; - // We need standalone months for these strings in Persian (fa): http://b/6811327 - if (!numericDate && !abbrevMonth && Locale.getDefault().getLanguage().equals("fa")) { - startStandaloneMonthString = startDate.format("%-B"); - endStandaloneMonthString = endDate.format("%-B"); - } - - if (startMonthNum != endMonthNum) { - // Same year, different month. - // Example: "October 28 - November 3" - // or: "Wed, Oct 31 - Sat, Nov 3, 2007" - // or: "Oct 31, 8am - Sat, Nov 3, 2007, 5pm" - - int index = 0; - if (showWeekDay) index = 1; - if (showYear) index += 2; - if (showTime) index += 4; - if (numericDate) index += 8; - int resId = sameYearTable[index]; - fullFormat = res.getString(resId); - - // The values that are used in a fullFormat string are specified - // by position. - return formatter.format(fullFormat, - startWeekDayString, startMonthString, startMonthDayString, - startYearString, startTimeString, - endWeekDayString, endMonthString, endMonthDayString, - endYearString, endTimeString, - startStandaloneMonthString, endStandaloneMonthString); - } - - if (startDay != endDay) { - // Same month, different day. - int index = 0; - if (showWeekDay) index = 1; - if (showYear) index += 2; - if (showTime) index += 4; - if (numericDate) index += 8; - int resId = sameMonthTable[index]; - fullFormat = res.getString(resId); - - // The values that are used in a fullFormat string are specified - // by position. - return formatter.format(fullFormat, - startWeekDayString, startMonthString, startMonthDayString, - startYearString, startTimeString, - endWeekDayString, endMonthString, endMonthDayString, - endYearString, endTimeString, - startStandaloneMonthString, endStandaloneMonthString); - } - - // Same start and end day - boolean showDate = (flags & FORMAT_SHOW_DATE) != 0; - - // If nothing was specified, then show the date. - if (!showTime && !showDate && !showWeekDay) showDate = true; - - // Compute the time string (example: "10:00 - 11:00 am") - String timeString = ""; - if (showTime) { - // If the start and end time are the same, then just show the - // start time. - if (isInstant) { - // Same start and end time. - // Example: "10:15 AM" - timeString = startTimeString; - } else { - // Example: "10:00 - 11:00 am" - String timeFormat = res.getString(com.android.internal.R.string.time1_time2); - // Don't use the user supplied Formatter because the result will pollute the buffer. - timeString = String.format(timeFormat, startTimeString, endTimeString); - } - } - - // Figure out which full format to use. - fullFormat = ""; - String dateString = ""; - if (showDate) { - dateString = startDate.format(defaultDateFormat); - if (showWeekDay) { - if (showTime) { - // Example: "10:00 - 11:00 am, Tue, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.time_wday_date); - } else { - // Example: "Tue, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.wday_date); - } - } else { - if (showTime) { - // Example: "10:00 - 11:00 am, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.time_date); - } else { - // Example: "Oct 9" - return formatter.format("%s", dateString); - } - } - } else if (showWeekDay) { - if (showTime) { - // Example: "10:00 - 11:00 am, Tue" - fullFormat = res.getString(com.android.internal.R.string.time_wday); - } else { - // Example: "Tue" - return formatter.format("%s", startWeekDayString); - } - } else if (showTime) { - return formatter.format("%s", timeString); - } - - // The values that are used in a fullFormat string are specified - // by position. - return formatter.format(fullFormat, timeString, startWeekDayString, dateString); - } - - private static void setTimeFromCalendar(Time t, Calendar c) { - t.hour = c.get(Calendar.HOUR_OF_DAY); - t.minute = c.get(Calendar.MINUTE); - t.month = c.get(Calendar.MONTH); - t.monthDay = c.get(Calendar.DAY_OF_MONTH); - t.second = c.get(Calendar.SECOND); - t.weekDay = c.get(Calendar.DAY_OF_WEEK) - 1; - t.year = c.get(Calendar.YEAR); - t.yearDay = c.get(Calendar.DAY_OF_YEAR); - t.isDst = (c.get(Calendar.DST_OFFSET) != 0) ? 1 : 0; - t.gmtoff = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET); - t.timezone = c.getTimeZone().getID(); + return formatter; } /** diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index 2bc1c6a..deb138d 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -365,7 +365,7 @@ public class Linkify { String scheme, MatchFilter matchFilter, TransformFilter transformFilter) { boolean hasMatches = false; - String prefix = (scheme == null) ? "" : scheme.toLowerCase(); + String prefix = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT); Matcher m = p.matcher(s); while (m.find()) { diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index 7e3c855..f607207 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -18,6 +18,7 @@ package android.util; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; +import java.util.Locale; /** * <p>Various utilities for debugging and logging.</p> @@ -78,7 +79,7 @@ public class DebugUtils { Class<?> parent = klass; do { declaredMethod = parent.getDeclaredMethod("get" + - pair[0].substring(0, 1).toUpperCase() + + pair[0].substring(0, 1).toUpperCase(Locale.ROOT) + pair[0].substring(1), (Class[]) null); } while ((parent = klass.getSuperclass()) != null && diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 366abd3..7e8fee5 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -118,7 +118,7 @@ public class SparseArray<E> implements Cloneable { mGarbage = true; } } - + private void gc() { // Log.e("SparseArray", "gc start with " + mSize); @@ -214,7 +214,7 @@ public class SparseArray<E> implements Cloneable { /** * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ public int keyAt(int index) { if (mGarbage) { @@ -223,11 +223,11 @@ public class SparseArray<E> implements Cloneable { return mKeys[index]; } - + /** * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ @SuppressWarnings("unchecked") public E valueAt(int index) { @@ -241,7 +241,7 @@ public class SparseArray<E> implements Cloneable { /** * Given an index in the range <code>0...size()-1</code>, sets a new * value for the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ public void setValueAt(int index, E value) { if (mGarbage) { @@ -250,7 +250,7 @@ public class SparseArray<E> implements Cloneable { mValues[index] = value; } - + /** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative number if the specified @@ -268,9 +268,11 @@ public class SparseArray<E> implements Cloneable { * Returns an index for which {@link #valueAt} would return the * specified key, or a negative number if no keys map to the * specified value. - * Beware that this is a linear search, unlike lookups by key, + * <p>Beware that this is a linear search, unlike lookups by key, * and that multiple keys can map to the same value and this will * find only one of them. + * <p>Note also that unlike most collections' {@code indexOf} methods, + * this method compares values using {@code ==} rather than {@code equals}. */ public int indexOfValue(E value) { if (mGarbage) { @@ -332,7 +334,7 @@ public class SparseArray<E> implements Cloneable { mValues[pos] = value; mSize = pos + 1; } - + private static int binarySearch(int[] a, int start, int len, int key) { int high = start + len, low = start - 1, guess; diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 5a4f322..33964a0 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -235,7 +235,7 @@ public class TimeUtils { * during the lifetime of an activity. */ public static String getTimeZoneDatabaseVersion() { - return ZoneInfoDB.getVersion(); + return ZoneInfoDB.getInstance().getVersion(); } /** @hide Field length that can hold 999 days of time */ diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 0546d24..5db3909 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -634,8 +634,8 @@ public class KeyEvent extends InputEvent implements Parcelable { // NOTE: If you add a new keycode here you must also add it to: // isSystem() - // native/include/android/keycodes.h - // frameworks/base/include/ui/KeycodeLabels.h + // frameworks/native/include/android/keycodes.h + // frameworks/base/include/androidfw/KeycodeLabels.h // external/webkit/WebKit/android/plugins/ANPKeyCodes.h // frameworks/base/core/res/res/values/attrs.xml // emulator? diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 01d80ac..50638aa 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10680,8 +10680,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * handler can be used to pump events in the UI events queue. */ public Handler getHandler() { - if (mAttachInfo != null) { - return mAttachInfo.mHandler; + final AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + return attachInfo.mHandler; } return null; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 95d65eb..3aa4cfb 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1509,9 +1509,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (lastHoverTarget != null) { lastHoverTarget.next = hoverTarget; } else { - lastHoverTarget = hoverTarget; mFirstHoverTarget = hoverTarget; } + lastHoverTarget = hoverTarget; // Dispatch the event to the child. if (action == MotionEvent.ACTION_HOVER_ENTER) { diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index 71a85bc..e6bf420 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -98,6 +98,12 @@ public class ViewPropertyAnimator { private Animator.AnimatorListener mListener = null; /** + * A lazily-created ValueAnimator used in order to get some default animator properties + * (duration, start delay, interpolator, etc.). + */ + private ValueAnimator mTempValueAnimator; + + /** * This listener is the mechanism by which the underlying Animator causes changes to the * properties currently being animated, as well as the cleanup after an animation is * complete. @@ -268,7 +274,10 @@ public class ViewPropertyAnimator { } else { // Just return the default from ValueAnimator, since that's what we'd get if // the value has not been set otherwise - return new ValueAnimator().getDuration(); + if (mTempValueAnimator == null) { + mTempValueAnimator = new ValueAnimator(); + } + return mTempValueAnimator.getDuration(); } } @@ -328,7 +337,16 @@ public class ViewPropertyAnimator { * @return The timing interpolator for this animation. */ public TimeInterpolator getInterpolator() { - return null; + if (mInterpolatorSet) { + return mInterpolator; + } else { + // Just return the default from ValueAnimator, since that's what we'd get if + // the value has not been set otherwise + if (mTempValueAnimator == null) { + mTempValueAnimator = new ValueAnimator(); + } + return mTempValueAnimator.getInterpolator(); + } } /** diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index ce886f2..6955d14 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -40,13 +40,13 @@ import android.view.WindowManager; import junit.framework.Assert; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URLEncoder; -import java.nio.charset.Charsets; import java.security.PrivateKey; -import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; @@ -55,9 +55,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; -import org.apache.harmony.security.provider.cert.X509CertImpl; -import org.apache.harmony.xnet.provider.jsse.OpenSSLKey; -import org.apache.harmony.xnet.provider.jsse.OpenSSLKeyHolder; +import com.android.org.conscrypt.OpenSSLKey; +import com.android.org.conscrypt.OpenSSLKeyHolder; class BrowserFrame extends Handler { @@ -1081,10 +1080,12 @@ class BrowserFrame extends Handler { String url) { final SslError sslError; try { - X509Certificate cert = new X509CertImpl(certDER); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate( + new ByteArrayInputStream(certDER)); SslCertificate sslCert = new SslCertificate(cert); sslError = SslError.SslErrorFromChromiumErrorCode(certError, sslCert, url); - } catch (IOException e) { + } catch (Exception e) { // Can't get the certificate, not much to do. Log.e(LOGTAG, "Can't get the certificate from WebKit, canceling"); nativeSslCertErrorCancel(handle, certError); @@ -1202,9 +1203,11 @@ class BrowserFrame extends Handler { */ private void setCertificate(byte cert_der[]) { try { - X509Certificate cert = new X509CertImpl(cert_der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate( + new ByteArrayInputStream(cert_der)); mCallbackProxy.onReceivedCertificate(new SslCertificate(cert)); - } catch (IOException e) { + } catch (Exception e) { // Can't get the certificate, not much to do. Log.e(LOGTAG, "Can't get the certificate from WebKit, canceling"); return; diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 312af71..fea6be6 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -296,7 +296,12 @@ class CallbackProxy extends Handler { // in the UI thread. The WebViewClient and WebChromeClient functions // that check for a non-null callback are ok because java ensures atomic // 32-bit reads and writes. - if (messagesBlocked()) return; + if (messagesBlocked()) { + synchronized (this) { + notify(); + } + return; + } switch (msg.what) { case PAGE_STARTED: String startedUrl = msg.getData().getString("url"); diff --git a/core/java/android/webkit/ClientCertRequestHandler.java b/core/java/android/webkit/ClientCertRequestHandler.java index f5a60f6..d7a6806 100644 --- a/core/java/android/webkit/ClientCertRequestHandler.java +++ b/core/java/android/webkit/ClientCertRequestHandler.java @@ -20,9 +20,9 @@ import android.os.Handler; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import org.apache.harmony.xnet.provider.jsse.NativeCrypto; -import org.apache.harmony.xnet.provider.jsse.OpenSSLKey; -import org.apache.harmony.xnet.provider.jsse.OpenSSLKeyHolder; +import com.android.org.conscrypt.NativeCrypto; +import com.android.org.conscrypt.OpenSSLKey; +import com.android.org.conscrypt.OpenSSLKeyHolder; /** * ClientCertRequestHandler: class responsible for handling client diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index b47f04f..d115984 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -17,6 +17,7 @@ package android.webkit; import java.io.UnsupportedEncodingException; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -348,7 +349,7 @@ public final class URLUtil { } } if (extension == null) { - if (mimeType != null && mimeType.toLowerCase().startsWith("text/")) { + if (mimeType != null && mimeType.toLowerCase(Locale.ROOT).startsWith("text/")) { if (mimeType.equalsIgnoreCase("text/html")) { extension = ".html"; } else { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 219891c..c36ecc8 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -919,9 +919,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * the choice mode has not been set to {@link #CHOICE_MODE_NONE}. * * @return A SparseBooleanArray which will return true for each call to - * get(int position) where position is a position in the list, - * or <code>null</code> if the choice mode is set to - * {@link #CHOICE_MODE_NONE}. + * get(int position) where position is a checked position in the + * list and false otherwise, or <code>null</code> if the choice + * mode is set to {@link #CHOICE_MODE_NONE}. */ public SparseBooleanArray getCheckedItemPositions() { if (mChoiceMode != CHOICE_MODE_NONE) { diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 36d33e7..6970cde 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -247,7 +247,7 @@ public class CalendarView extends FrameLayout { /** * Which month should be displayed/highlighted [0-11]. */ - private int mCurrentMonthDisplayed; + private int mCurrentMonthDisplayed = -1; /** * Used for tracking during a scroll. diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index de8b80d..3f080d6 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -242,7 +242,7 @@ public class CheckedTextView extends TextView implements Checkable { right = width - mBasePadding; left = right - mCheckMarkWidth; } - checkMarkDrawable.setBounds( left, top, right, bottom); + checkMarkDrawable.setBounds(mScrollX + left, top, mScrollX + right, bottom); checkMarkDrawable.draw(canvas); } } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 8f515f5..d03161e 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -23,6 +23,7 @@ import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.text.InputType; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; @@ -38,6 +39,7 @@ import android.widget.NumberPicker.OnValueChangeListener; import com.android.internal.R; +import java.text.DateFormatSymbols; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -45,6 +47,8 @@ import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; +import libcore.icu.ICU; + /** * This class is a widget for selecting a date. The date can be selected by a * year, month, and day spinners or a {@link CalendarView}. The set of spinners @@ -477,14 +481,27 @@ public class DatePicker extends FrameLayout { mCurrentDate = getCalendarForLocale(mCurrentDate, locale); mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1; - mShortMonths = new String[mNumberOfMonths]; - for (int i = 0; i < mNumberOfMonths; i++) { - mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, - DateUtils.LENGTH_MEDIUM); + mShortMonths = new DateFormatSymbols().getShortMonths(); + + if (usingNumericMonths()) { + // We're in a locale where a date should either be all-numeric, or all-text. + // All-text would require custom NumberPicker formatters for day and year. + mShortMonths = new String[mNumberOfMonths]; + for (int i = 0; i < mNumberOfMonths; ++i) { + mShortMonths[i] = String.format("%d", i + 1); + } } } /** + * Tests whether the current locale is one where there are no real month names, + * such as Chinese, Japanese, or Korean locales. + */ + private boolean usingNumericMonths() { + return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0)); + } + + /** * Gets a calendar for locale bootstrapped with the value of a given calendar. * * @param oldCalendar The old calendar. @@ -508,24 +525,27 @@ public class DatePicker extends FrameLayout { */ private void reorderSpinners() { mSpinners.removeAllViews(); - char[] order = DateFormat.getDateFormatOrder(getContext()); + // We use numeric spinners for year and day, but textual months. Ask icu4c what + // order the user's locale uses for that combination. http://b/7207103. + String pattern = ICU.getBestDateTimePattern("yyyyMMMdd", Locale.getDefault().toString()); + char[] order = ICU.getDateFormatOrder(pattern); final int spinnerCount = order.length; for (int i = 0; i < spinnerCount; i++) { switch (order[i]) { - case DateFormat.DATE: + case 'd': mSpinners.addView(mDaySpinner); setImeOptions(mDaySpinner, spinnerCount, i); break; - case DateFormat.MONTH: + case 'M': mSpinners.addView(mMonthSpinner); setImeOptions(mMonthSpinner, spinnerCount, i); break; - case DateFormat.YEAR: + case 'y': mSpinners.addView(mYearSpinner); setImeOptions(mYearSpinner, spinnerCount, i); break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException(Arrays.toString(order)); } } } @@ -660,6 +680,10 @@ public class DatePicker extends FrameLayout { mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR)); mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH)); mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); + + if (usingNumericMonths()) { + mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER); + } } /** diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index fc9c000..10b8cbe 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -676,8 +676,13 @@ class FastScroller { final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem); final int sectionPos = mSectionIndexer.getPositionForSection(section); - final int nextSectionPos = mSectionIndexer.getPositionForSection(section + 1); + final int nextSectionPos; final int sectionCount = mSections.length; + if (section + 1 < sectionCount) { + nextSectionPos = mSectionIndexer.getPositionForSection(section + 1); + } else { + nextSectionPos = totalItemCount - 1; + } final int positionsInSection = nextSectionPos - sectionPos; final View child = mList.getChildAt(0); diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java index e2a269e..f9d8f92 100644 --- a/core/java/android/widget/HeaderViewListAdapter.java +++ b/core/java/android/widget/HeaderViewListAdapter.java @@ -144,7 +144,7 @@ public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { } public boolean isEnabled(int position) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) + // Header (negative positions will throw an IndexOutOfBoundsException) int numHeaders = getHeadersCount(); if (position < numHeaders) { return mHeaderViewInfos.get(position).isSelectable; @@ -160,12 +160,12 @@ public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { } } - // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException) + // Footer (off-limits positions will throw an IndexOutOfBoundsException) return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable; } public Object getItem(int position) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) + // Header (negative positions will throw an IndexOutOfBoundsException) int numHeaders = getHeadersCount(); if (position < numHeaders) { return mHeaderViewInfos.get(position).data; @@ -181,7 +181,7 @@ public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { } } - // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException) + // Footer (off-limits positions will throw an IndexOutOfBoundsException) return mFooterViewInfos.get(adjPosition - adapterCount).data; } @@ -205,7 +205,7 @@ public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { } public View getView(int position, View convertView, ViewGroup parent) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) + // Header (negative positions will throw an IndexOutOfBoundsException) int numHeaders = getHeadersCount(); if (position < numHeaders) { return mHeaderViewInfos.get(position).view; @@ -221,7 +221,7 @@ public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { } } - // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException) + // Footer (off-limits positions will throw an IndexOutOfBoundsException) return mFooterViewInfos.get(adjPosition - adapterCount).view; } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 5392a96..65a2d4d 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -959,11 +959,9 @@ public class ProgressBar extends View { if (!mInDrawing) { if (verifyDrawable(dr)) { final Rect dirty = dr.getBounds(); - final int scrollX = mScrollX + mPaddingLeft; - final int scrollY = mScrollY + mPaddingTop; - invalidate(dirty.left + scrollX, dirty.top + scrollY, - dirty.right + scrollX, dirty.bottom + scrollY); + invalidate(dirty.left + mScrollX, dirty.top + mScrollY, + dirty.right + mScrollX, dirty.bottom + mScrollY); } else { super.invalidateDrawable(dr); } diff --git a/core/java/android/widget/SectionIndexer.java b/core/java/android/widget/SectionIndexer.java index 24f894c..a1c71f4 100644 --- a/core/java/android/widget/SectionIndexer.java +++ b/core/java/android/widget/SectionIndexer.java @@ -20,7 +20,9 @@ package android.widget; * Interface that should be implemented on Adapters to enable fast scrolling * in an {@link AbsListView} between sections of the list. A section is a group of list items * to jump to that have something in common. For example, they may begin with the - * same letter or they may be songs from the same artist. + * same letter or they may be songs from the same artist. ExpandableListAdapters that + * consider groups and sections as synonymous should account for collapsed groups and return + * an appropriate section/position. */ public interface SectionIndexer { /** diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index e6796cb..e33c4d4 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -237,6 +237,7 @@ public class TimePicker extends FrameLayout { // update controls to initial state updateHourControl(); + updateMinuteControl(); updateAmPmControl(); setOnTimeChangedListener(NO_OP_CHANGE_LISTENER); @@ -428,6 +429,7 @@ public class TimePicker extends FrameLayout { updateHourControl(); // set value after spinner range is updated setCurrentHour(currentHour); + updateMinuteControl(); updateAmPmControl(); } @@ -508,6 +510,14 @@ public class TimePicker extends FrameLayout { } } + private void updateMinuteControl() { + if (is24HourView()) { + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); + } else { + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + } + } + private void updateAmPmControl() { if (is24HourView()) { if (mAmPmSpinner != null) { |
