Merge change 26550 into eclair

* changes:
  fix bug 2134367: failing phone number compare test.
diff --git a/api/current.xml b/api/current.xml
index 68a1c76..581d2c4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -8259,6 +8259,17 @@
  visibility="public"
 >
 </field>
+<field name="thumbnail"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843429"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="tileMode"
  type="int"
  transient="false"
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 9afeb74..1ee7f60 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -807,6 +807,10 @@
      * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
      * The listener is guaranteed to be invoked on the thread of the Handler that is passed
      * in or the main thread's Handler if handler is null.
+     * <p>
+     * You must remove this listener before the context that was used to retrieve this
+     * {@link AccountManager} instance goes away. This generally means when the Activity
+     * or Service you are running is stopped.
      * @param listener the listener to add
      * @param handler the Handler whose thread will be used to invoke the listener. If null
      * the AccountManager context's main thread will be used.
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index afafe64..8896015 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -153,7 +153,6 @@
     private final static boolean DEBUG_ICONS = false;
 
     private static final Object sSync = new Object();
-    private static AccountManager sAccountManager;
     private static AlarmManager sAlarmManager;
     private static PowerManager sPowerManager;
     private static ConnectivityManager sConnectivityManager;
@@ -186,6 +185,7 @@
     private boolean mIsBluetoothAdapterCached = false;
     private BluetoothAdapter mBluetoothAdapter;
     private boolean mRestricted;
+    private AccountManager mAccountManager; // protected by mSync
 
     private final Object mSync = new Object();
 
@@ -908,14 +908,14 @@
     }
 
     private AccountManager getAccountManager() {
-        synchronized (sSync) {
-            if (sAccountManager == null) {
+        synchronized (mSync) {
+            if (mAccountManager == null) {
                 IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
                 IAccountManager service = IAccountManager.Stub.asInterface(b);
-                sAccountManager = new AccountManager(this, service);
+                mAccountManager = new AccountManager(this, service);
             }
+            return mAccountManager;
         }
-        return sAccountManager;
     }
 
     private ActivityManager getActivityManager() {
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 5e44bc7..587e8f9 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -40,6 +40,11 @@
     final String mSettingsActivityName;
 
     /**
+     * Resource identifier for this wallpaper's thumbnail image.
+     */
+    final int mThumbnailResource;
+
+    /**
      * Constructor.
      * 
      * @param context The Context in which we are parsing the wallpaper.
@@ -53,6 +58,7 @@
         
         PackageManager pm = context.getPackageManager();
         String settingsActivityComponent = null;
+        int thumbnailRes = -1;
         
         XmlResourceParser parser = null;
         try {
@@ -79,16 +85,23 @@
                     com.android.internal.R.styleable.Wallpaper);
             settingsActivityComponent = sa.getString(
                     com.android.internal.R.styleable.Wallpaper_settingsActivity);
+            
+            thumbnailRes = sa.getResourceId(
+                    com.android.internal.R.styleable.Wallpaper_thumbnail,
+                    -1);
+
             sa.recycle();
         } finally {
             if (parser != null) parser.close();
         }
         
         mSettingsActivityName = settingsActivityComponent;
+        mThumbnailResource = thumbnailRes;
     }
 
     WallpaperInfo(Parcel source) {
         mSettingsActivityName = source.readString();
+        mThumbnailResource = source.readInt();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
     }
     
@@ -144,6 +157,20 @@
     }
     
     /**
+     * Load the thumbnail image for this wallpaper.
+     * 
+     * @param pm Supply a PackageManager used to load the wallpaper's
+     * resources.
+     */
+    public Drawable loadThumbnail(PackageManager pm) {
+        if (mThumbnailResource < 0) return null;
+
+        return pm.getDrawable(mService.serviceInfo.packageName,
+                              mThumbnailResource,
+                              null);
+    }
+    
+    /**
      * Return the class name of an activity that provides a settings UI for
      * the wallpaper.  You can launch this activity be starting it with
      * an {@link android.content.Intent} whose action is MAIN and with an
@@ -178,6 +205,7 @@
      */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mSettingsActivityName);
+        dest.writeInt(mThumbnailResource);
         mService.writeToParcel(dest, flags);
     }
 
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 80613d8..eff6f52 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -244,7 +244,7 @@
             // If this was the bootup case then don't sync everything, instead only
             // sync those that have an unknown syncable state, which will give them
             // a chance to set their syncable state.
-            boolean onlyThoseWithUnkownSyncableState = !justBootedUp;
+            boolean onlyThoseWithUnkownSyncableState = justBootedUp;
             scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState);
         }
     }
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 4e6f9ca..c782c8c 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -25,6 +25,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.Build;
 import android.server.data.CrashData;
 import android.util.Config;
 import android.util.Log;
@@ -111,6 +112,12 @@
         new AndroidConfig();
 
         /*
+         * Sets the default HTTP User-Agent used by HttpURLConnection.
+         */
+        String userAgent = getDefaultUserAgent();
+        System.setProperty("http.agent", userAgent);
+
+        /*
          * If we're running in an emulator launched with "-trace", put the
          * VM into emulator trace profiling mode so that the user can hit
          * F9/F10 at any time to capture traces.  This has performance
@@ -126,6 +133,36 @@
     }
 
     /**
+     * Returns an HTTP user agent of the form
+     * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
+     */
+    private static String getDefaultUserAgent() {
+        StringBuilder result = new StringBuilder(64);
+        result.append("Dalvik/");
+        result.append(System.getProperty("java.vm.version")); // such as 1.1.0
+        result.append(" (Linux; U; Android ");
+
+        String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
+        result.append(version.length() > 0 ? version : "1.0");
+
+        // add the model for the release build
+        if ("REL".equals(Build.VERSION.CODENAME)) {
+            String model = Build.MODEL;
+            if (model.length() > 0) {
+                result.append("; ");
+                result.append(model);
+            }
+        }
+        String id = Build.ID; // "MASTER" or "M4-rc20"
+        if (id.length() > 0) {
+            result.append(" Build/");
+            result.append(id);
+        }
+        result.append(")");
+        return result.toString();
+    }
+
+    /**
      * Invokes a static "main(argv[]) method on class "className".
      * Converts various failing exceptions into RuntimeExceptions, with
      * the assumption that they will then cause the VM instance to exit.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a0d046f..193fdb2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3451,6 +3451,9 @@
         <!-- Component name of an activity that allows the user to modify
              the current settings for this wallpaper. -->
         <attr name="settingsActivity" />
+
+        <!-- Reference to a the wallpaper's thumbnail bitmap. -->
+        <attr name="thumbnail" format="reference" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7aeaec4..a32f519 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -79,12 +79,16 @@
     <integer name="config_carDockRotation">-1</integer>
 
     <!-- Control whether being in the desk dock (and powered) always
-         keeps the screen on.  By default it doesn't.  Set to true to make it. -->
-    <bool name="config_deskDockKeepsScreenOn">false</bool>
+         keeps the screen on.  By default it stays on when plugged in to
+         AC.  0 will not keep it on; or together 1 to stay on when plugged
+         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
+    <integer name="config_deskDockKeepsScreenOn">1</integer>
 
     <!-- Control whether being in the car dock (and powered) always
-         keeps the screen on.  By default it does.  Set to false to not keep on. -->
-    <bool name="config_carDockKeepsScreenOn">true</bool>
+         keeps the screen on.  By default it stays on when plugged in to
+         AC.  0 will not keep it on; or together 1 to stay on when plugged
+         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
+    <integer name="config_carDockKeepsScreenOn">1</integer>
 
     <!-- Control whether being in the desk dock should enable accelerometer based screen orientation -->
     <bool name="config_deskDockEnablesAccelerometer">false</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b08a58a..4d23ef4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1169,6 +1169,7 @@
   <public type="attr" name="summaryColumn" />
   <public type="attr" name="detailColumn" />
   <public type="attr" name="detailSocialSummary" />
+  <public type="attr" name="thumbnail" />
 
   <public type="style" name="Theme.Wallpaper" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar" />
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index d78d886..53edf31 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -267,6 +267,20 @@
                 logOutlier = true;
             }
             
+            final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+            final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+            /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+             * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
+             * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
+             */
+            final boolean sendBatteryLow = !plugged
+                && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+                && mBatteryLevel < BATTERY_LEVEL_WARNING
+                && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
+            
+            sendIntent();
+            
             // Separate broadcast is sent for power connected / not connected
             // since the standard intent will not wake any applications and some
             // applications may want to have smart behavior based on this.
@@ -281,28 +295,6 @@
                 mContext.sendBroadcast(statusIntent);
             }
 
-            final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
-            final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
-
-            /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
-             * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
-             * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
-             */
-            final boolean sendBatteryLow = !plugged
-                && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
-                && mBatteryLevel < BATTERY_LEVEL_WARNING
-                && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
-            
-            mLastBatteryStatus = mBatteryStatus;
-            mLastBatteryHealth = mBatteryHealth;
-            mLastBatteryPresent = mBatteryPresent;
-            mLastBatteryLevel = mBatteryLevel;
-            mLastPlugType = mPlugType;
-            mLastBatteryVoltage = mBatteryVoltage;
-            mLastBatteryTemperature = mBatteryTemperature;
-            mLastBatteryLevelCritical = mBatteryLevelCritical;
-
-            sendIntent();
             if (sendBatteryLow) {
                 mSentLowBatteryBroadcast = true;
                 statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
@@ -317,6 +309,15 @@
             if (logOutlier && dischargeDuration != 0) {
                 logOutlier(dischargeDuration);
             }
+            
+            mLastBatteryStatus = mBatteryStatus;
+            mLastBatteryHealth = mBatteryHealth;
+            mLastBatteryPresent = mBatteryPresent;
+            mLastBatteryLevel = mBatteryLevel;
+            mLastPlugType = mPlugType;
+            mLastBatteryVoltage = mBatteryVoltage;
+            mLastBatteryTemperature = mBatteryTemperature;
+            mLastBatteryLevelCritical = mBatteryLevelCritical;
         }
     }
 
diff --git a/tests/CoreTests/android/core/URLTest.java b/tests/CoreTests/android/core/URLTest.java
index 56f9f7b..5efcd5b 100644
--- a/tests/CoreTests/android/core/URLTest.java
+++ b/tests/CoreTests/android/core/URLTest.java
@@ -16,6 +16,7 @@
 
 package android.core;
 
+import android.test.suitebuilder.annotation.Suppress;
 import junit.framework.TestCase;
 
 import java.io.BufferedReader;
@@ -29,10 +30,9 @@
 import java.net.Socket;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
 
-import android.test.suitebuilder.annotation.Suppress;
-
-@Suppress
 public class URLTest extends TestCase {
 
     private static void get(String u) throws IOException {
@@ -63,10 +63,12 @@
         assertTrue(new String(data).indexOf("<html>") >= 0);
     }
 
+    @Suppress
     public void testGetHTTP() throws Exception {
         get("http://www.google.com");
     }
 
+    @Suppress
     public void testGetHTTPS() throws Exception {
         get("https://www.fortify.net/cgi/ssl_2.pl");
     }
@@ -79,6 +81,7 @@
     private static class DummyServer implements Runnable {
 
         private int keepAliveCount;
+        private Map<String, String> headers = new HashMap<String, String>();
 
         public DummyServer(int keepAliveCount) {
             this.keepAliveCount = keepAliveCount;
@@ -93,9 +96,17 @@
                 BufferedReader reader = new BufferedReader(new InputStreamReader(input));
                 try {
                     for (int i = 0; i < keepAliveCount; i++) {
-                        String header = reader.readLine();
-                        while (header != null && header.length() != 0) {
-                            header = reader.readLine();
+                        reader.readLine();
+                        headers.clear();
+                        while (true) {
+                            String header = reader.readLine();
+                            if (header.length() == 0) {
+                                break;
+                            }
+                            int colon = header.indexOf(":");
+                            String key = header.substring(0, colon);
+                            String value = header.substring(colon + 1).trim();
+                            headers.put(key, value);
                         }
 
                         OutputStream output = socket.getOutputStream();
@@ -142,6 +153,7 @@
     /**
      * Test case for HTTP keep-alive behavior.
      */
+    @Suppress
     public void testGetKeepAlive() throws Exception {
         new Thread(new DummyServer(3)).start();
         Thread.sleep(100);
@@ -160,9 +172,24 @@
         }
     }
 
+    @Suppress
+    public void testUserAgentHeader() throws Exception {
+        DummyServer server = new DummyServer(1);
+        new Thread(server).start();
+        Thread.sleep(100);
+
+        // We expect the request to work three times, then it fails.
+        request(new URL("http://localhost:8182"));
+
+        String userAgent = server.headers.get("User-Agent");
+        assertTrue("Unexpected User-Agent: " + userAgent, userAgent.matches(
+                "Dalvik/[\\d.]+ \\(Linux; U; Android \\w+(;.*)?( Build/\\w+)?\\)"));
+    }
+
     /**
      * Regression for issue 1001814.
      */
+    @Suppress
     public void testHttpConnectionTimeout() throws Exception {
         int timeout = 5000;
         HttpURLConnection cn = null;
@@ -190,7 +217,8 @@
     /** 
      * Regression test for issue 1158780 where using '{' and '}' in an URL threw
      * an NPE. The RI accepts this URL and returns the status 404.
-     */ 
+     */
+    @Suppress
     public void testMalformedUrl() throws Exception {
         URL url = new URL("http://www.google.com/cgi-bin/myscript?g={United+States}+Borders+Mexico+{Climate+change}+Marketing+{Automotive+industry}+News+Health+Internet");
         HttpURLConnection conn = (HttpURLConnection)url.openConnection();
diff --git a/tools/layoutlib/api/src/com/android/layoutlib/api/IDensityBasedResourceValue.java b/tools/layoutlib/api/src/com/android/layoutlib/api/IDensityBasedResourceValue.java
new file mode 100644
index 0000000..fb9387f
--- /dev/null
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/IDensityBasedResourceValue.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.api;
+
+/**
+ * Represents an Android Resources that has a density info attached to it.
+ */
+public interface IDensityBasedResourceValue extends IResourceValue {
+    public static enum Density {
+        HIGH, MEDIUM, LOW, NODPI;
+    }
+
+    /**
+     * Returns the density associated to the resource.
+     */
+    Density getDensity();
+}