Merge change 9073 into donut

* changes:
  Special-case search within the browser to not show the app icon to the left of the search field. Also, because this removes context about whether you're in browser search or global search, we make sure to clear any entered text if you jump out to global search from within browser search.
diff --git a/api/current.xml b/api/current.xml
index 337a3d3..4df50bc 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -79956,6 +79956,19 @@
  visibility="public"
 >
 </method>
+<method name="setReferenceCounted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="refCounted" type="boolean">
+</parameter>
+</method>
 </class>
 <class name="WifiManager.WifiLock"
  extends="java.lang.Object"
@@ -130429,9 +130442,33 @@
  type="android.text.style.ImageSpan"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="b" type="android.graphics.Bitmap">
+</parameter>
+</constructor>
+<constructor name="ImageSpan"
+ type="android.text.style.ImageSpan"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="b" type="android.graphics.Bitmap">
+</parameter>
+<parameter name="verticalAlignment" type="int">
+</parameter>
+</constructor>
+<constructor name="ImageSpan"
+ type="android.text.style.ImageSpan"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="context" type="android.content.Context">
+</parameter>
 <parameter name="b" type="android.graphics.Bitmap">
 </parameter>
 </constructor>
@@ -130442,6 +130479,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="context" type="android.content.Context">
+</parameter>
 <parameter name="b" type="android.graphics.Bitmap">
 </parameter>
 <parameter name="verticalAlignment" type="int">
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 911a23c..86ef5f6 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -33,17 +33,34 @@
     private Context mContext;
     private String mSource;
 
+    /**
+     * @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead.
+     */
     public ImageSpan(Bitmap b) {
-        this(b, ALIGN_BOTTOM);
+        this(null, b, ALIGN_BOTTOM);
+    }
+
+    /**
+     * @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead.
+     */
+    public ImageSpan(Bitmap b, int verticalAlignment) {
+        this(null, b, verticalAlignment);
+    }
+
+    public ImageSpan(Context context, Bitmap b) {
+        this(context, b, ALIGN_BOTTOM);
     }
 
     /**
      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
      * {@link DynamicDrawableSpan#ALIGN_BASELINE}.
      */
-    public ImageSpan(Bitmap b, int verticalAlignment) {
+    public ImageSpan(Context context, Bitmap b, int verticalAlignment) {
         super(verticalAlignment);
-        mDrawable = new BitmapDrawable(mContext.getResources(), b);
+        mContext = context;
+        mDrawable = context != null
+                ? new BitmapDrawable(context.getResources(), b)
+                : new BitmapDrawable(b);
         int width = mDrawable.getIntrinsicWidth();
         int height = mDrawable.getIntrinsicHeight();
         mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0); 
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 63c9eaa..55007ba 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -323,15 +323,22 @@
      */
     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
             boolean isDefault) {
-        for (int i = 0, count = mServices.size(); i < count; i++) {
-            Service service = mServices.get(i);
+        try {
+            for (int i = 0, count = mServices.size(); i < count; i++) {
+                Service service = mServices.get(i);
 
-            if (service.mIsDefault == isDefault) {
-                if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) {
-                    mHandledFeedbackTypes |= service.mFeedbackType;
-                    notifyAccessibilityServiceDelayedLocked(service, event);
+                if (service.mIsDefault == isDefault) {
+                    if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) {
+                        mHandledFeedbackTypes |= service.mFeedbackType;
+                        notifyAccessibilityServiceDelayedLocked(service, event);
+                    }
                 }
             }
+        } catch (IndexOutOfBoundsException oobe) {
+            // An out of bounds exception can happen if services are going away
+            // as the for loop is running. If that happens, just bail because
+            // there are no more services to notify.
+            return;
         }
     }
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java b/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java
index 7dc1314..67fcd61 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java
@@ -16,10 +16,22 @@
 
 package com.android.unit_tests;
 
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.vpn.L2tpProfile;
 import android.net.vpn.L2tpIpsecProfile;
+import android.net.vpn.L2tpIpsecPskProfile;
+import android.net.vpn.PptpProfile;
+import android.net.vpn.VpnManager;
+import android.net.vpn.VpnProfile;
+import android.net.vpn.VpnState;
 import android.net.vpn.VpnType;
+import android.os.ConditionVariable;
+import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 
 /**
  * Unit test class to test VPN api
@@ -29,6 +41,12 @@
  *   -w com.android.unit_tests/android.test.InstrumentationTestRunner
  */
 public class VpnTest extends AndroidTestCase {
+    private static final String NAME = "a name";
+    private static final String SERVER_NAME = "a server name";
+    private static final String ID = "some id";
+    private static final String SUFFICES = "some suffices";
+    private static final String ROUTES = "some routes";
+    private static final String SAVED_NAME = "some name";
 
     @Override
     public void setUp() {
@@ -39,8 +57,102 @@
     }
 
     @SmallTest
+    public void testVpnType() {
+        testVpnType(VpnType.L2TP);
+        testVpnType(VpnType.L2TP_IPSEC);
+        testVpnType(VpnType.L2TP_IPSEC_PSK);
+        testVpnType(VpnType.PPTP);
+    }
+
+    @SmallTest
+    public void testVpnProfile() {
+        VpnState state = VpnState.CONNECTING;
+        testVpnProfile(createTestProfile(state), state);
+    }
+
+    @SmallTest
     public void testGetType() {
-        L2tpIpsecProfile li = new L2tpIpsecProfile();
-        assertTrue(VpnType.L2TP_IPSEC== li.getType());
+        assertEquals(VpnType.L2TP, new L2tpProfile().getType());
+        assertEquals(VpnType.L2TP_IPSEC, new L2tpIpsecProfile().getType());
+        assertEquals(VpnType.L2TP_IPSEC_PSK, 
+                new L2tpIpsecPskProfile().getType());
+        assertEquals(VpnType.PPTP, new PptpProfile().getType());
+    }
+
+    @SmallTest
+    public void testVpnTypes() {
+        assertTrue(VpnManager.getSupportedVpnTypes().length > 0);
+    }
+
+    @SmallTest
+    public void testGetTypeFromManager() {
+        VpnManager m = new VpnManager(getContext());
+        VpnType[] types = VpnManager.getSupportedVpnTypes();
+        for (VpnType t : types) {
+            assertEquals(t, m.createVpnProfile(t).getType());
+        }
+    }
+
+    @SmallTest
+    public void testParcelable() {
+        VpnProfile p = createTestProfile(VpnState.CONNECTED);
+        Parcel parcel = Parcel.obtain();
+        p.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        // VpnState is transient and not saved in the parcel
+        testVpnProfile(VpnProfile.CREATOR.createFromParcel(parcel), null);
+    }
+
+    @SmallTest
+    public void testReceiver() {
+        final String profileName = "whatever";
+        final VpnState state = VpnState.DISCONNECTING;
+        final ConditionVariable cv = new ConditionVariable();
+        cv.close();
+        BroadcastReceiver r = new BroadcastReceiver() {
+            public void onReceive(Context c, Intent i) {
+                assertEquals(profileName,
+                        i.getStringExtra(VpnManager.BROADCAST_PROFILE_NAME));
+                assertEquals(state, i.getSerializableExtra(
+                        VpnManager.BROADCAST_CONNECTION_STATE));
+                cv.open();
+            }
+        };
+
+        VpnManager m = new VpnManager(getContext());
+        m.registerConnectivityReceiver(r);
+        m.broadcastConnectivity(profileName, state);
+
+        // fail it if onReceive() doesn't get executed in 5 sec
+        assertTrue(cv.block(5000));
+    }
+
+    private void testVpnType(VpnType type) {
+        assertFalse(TextUtils.isEmpty(type.getDisplayName()));
+        assertNotNull(type.getDescription());
+        assertNotNull(type.getProfileClass());
+    }
+
+    private VpnProfile createTestProfile(VpnState state) {
+        VpnProfile p = new L2tpProfile();
+        p.setName(NAME);
+        p.setServerName(SERVER_NAME);
+        p.setId(ID);
+        p.setDomainSuffices(SUFFICES);
+        p.setRouteList(ROUTES);
+        p.setSavedUsername(SAVED_NAME);
+        p.setState(state);
+        return p;
+    }
+
+    private void testVpnProfile(VpnProfile p, VpnState state) {
+        assertEquals(NAME, p.getName());
+        assertEquals(SERVER_NAME, p.getServerName());
+        assertEquals(ID, p.getId());
+        assertEquals(SUFFICES, p.getDomainSuffices());
+        assertEquals(ROUTES, p.getRouteList());
+        assertEquals(SAVED_NAME, p.getSavedUsername());
+        if (state != null) assertEquals(state, p.getState());
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1f73bec..74f4284 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -870,7 +870,10 @@
      * Create a new MulticastLock
      *
      * @param tag a tag for the MulticastLock to identify it in debugging
-     *            messages.
+     *            messages.  This string is never shown to the user under
+     *            normal conditions, but should be descriptive enough to
+     *            identify your application and the specific MulticastLock
+     *            within it, if it holds multiple MulticastLocks.
      *
      * @return a new, unacquired MulticastLock with the given tag.
      *
@@ -886,26 +889,36 @@
      * addressed to this device.  Acquring a MulticastLock will
      * cause the stack to receive packets addressed to multicast
      * addresses.  Processing these extra packets can cause a noticable
-     * battery drain and should be disabled when not needed
+     * battery drain and should be disabled when not needed.
      */
     public class MulticastLock {
         private String mTag;
         private final IBinder mBinder;
+        private int mRefCount;
+        private boolean mRefCounted;
         private boolean mHeld;
 
         private MulticastLock(String tag) {
             mTag = tag;
             mBinder = new Binder();
+            mRefCount = 0;
+            mRefCounted = true;
             mHeld = false;
         }
 
         /**
          * Locks Wifi Multicast on until {@link #release} is called.
          *
-         * The first call to {@code acquire} will lock the Multicast on
-         * but subsequent calls will be ignored.  Only one call to
-         * {@link #release} will be required, regardless of the number of
-         * times that {@code acquire} is called.
+         * If this MulticastLock is reference-counted each call to
+         * {@code acquire} will increment the reference count, and the
+         * wifi interface will receive multicast packets as long as the
+         * reference count is above zero.
+         *
+         * If this MulticastLock is not reference-counted, the first call to
+         * {@code acquire} will turn on the multicast packets, but subsequent
+         * calls will be ignored.  Only one call to {@link #release} will
+         * be required, regardless of the number of times that {@code acquire}
+         * is called.
          *
          * Note that other applications may also lock Wifi Multicast on.
          * Only they can relinquish their lock.
@@ -915,7 +928,7 @@
          */
         public void acquire() {
             synchronized (mBinder) {
-                if (!mHeld) {
+                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
                     try {
                         mService.acquireMulticastLock(mBinder, mTag);
                         synchronized (WifiManager.this) {
@@ -926,9 +939,9 @@
                             }
                             mActiveLockCount++;
                         }
-                        mHeld = true;
                     } catch (RemoteException ignore) {
                     }
+                    mHeld = true;
                 }
             }
         }
@@ -937,6 +950,18 @@
          * Unlocks Wifi Multicast, restoring the filter of packets
          * not addressed specifically to this device and saving power.
          *
+         * If this MulticastLock is reference-counted, each call to
+         * {@code release} will decrement the reference count, and the
+         * multicast packets will only stop being received when the reference
+         * count reaches zero.  If the reference count goes below zero (that
+         * is, if {@code release} is called a greater number of times than
+         * {@link #acquire}), an exception is thrown.
+         *
+         * If this MulticastLock is not reference-counted, the first call to
+         * {@code release} (after the radio was multicast locked using
+         * {@linke #acquire}) will unlock the multicast, and subsequent calls
+         * will be ignored.
+         *
          * Note that if any other Wifi Multicast Locks are still outstanding
          * this {@code release} call will not have an immediate effect.  Only
          * when all applications have released all their Multicast Locks will
@@ -947,20 +972,43 @@
          */
         public void release() {
             synchronized (mBinder) {
-                if (mHeld) {
+                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
                     try {
                         mService.releaseMulticastLock();
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                        mHeld = false;
                     } catch (RemoteException ignore) {
                     }
+                    mHeld = false;
+                }
+                if (mRefCount < 0) {
+                    throw new RuntimeException("MulticastLock under-locked "
+                            + mTag);
                 }
             }
         }
 
         /**
+         * Controls whether this is a reference-counted or non-reference-
+         * counted MulticastLock.
+         *
+         * Reference-counted MulticastLocks keep track of the number of calls
+         * to {@link #acquire} and {@link #release}, and only stop the
+         * reception of multicast packets when every call to {@link #acquire}
+         * has been balanced with a call to {@link #release}.  Non-reference-
+         * counted MulticastLocks allow the reception of multicast packets
+         * whenever {@link #acquire} is called and stop accepting multicast
+         * packets whenever {@link #release} is called.
+         *
+         * @param refCounted true if this MulticastLock should keep a reference
+         * count
+         */
+        public void setReferenceCounted(boolean refCounted) {
+            mRefCounted = refCounted;
+        }
+
+        /**
          * Checks whether this MulticastLock is currently held.
          *
          * @return true if this MulticastLock is held, false otherwise
@@ -972,17 +1020,23 @@
         }
 
         public String toString() {
-            String s1, s2;
+            String s1, s2, s3;
             synchronized (mBinder) {
                 s1 = Integer.toHexString(System.identityHashCode(this));
                 s2 = mHeld ? "held; " : "";
-                return "MulticastLock{ " + s1 + "; " + s2 + " }";
+                if (mRefCounted) {
+                    s3 = "refcounted: refcount = " + mRefCount;
+                } else {
+                    s3 = "not refcounted";
+                }
+                return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
             }
         }
 
         @Override
         protected void finalize() throws Throwable {
             super.finalize();
+            setReferenceCounted(false);
             release();
         }
     }