Merge change 2658

* changes:
  Delete the acc script when deleting the Renderscript rsScriptC object.
diff --git a/api/current.xml b/api/current.xml
index 4db6e66..f93fefd 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -309,6 +309,17 @@
  visibility="public"
 >
 </field>
+<field name="CHANGE_WIFI_MULTICAST_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.CHANGE_WIFI_MULTICAST_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CHANGE_WIFI_STATE"
  type="java.lang.String"
  transient="false"
@@ -80263,6 +80274,19 @@
 <parameter name="rssiB" type="int">
 </parameter>
 </method>
+<method name="createMulticastLock"
+ return="android.net.wifi.WifiManager.MulticastLock"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
 <method name="createWifiLock"
  return="android.net.wifi.WifiManager.WifiLock"
  abstract="false"
@@ -80755,6 +80779,48 @@
 >
 </field>
 </class>
+<class name="WifiManager.MulticastLock"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="acquire"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isHeld"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="WifiManager.WifiLock"
  extends="java.lang.Object"
  abstract="false"
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3c827a0..20e2c46 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3865,8 +3865,7 @@
             mRecognizer = LetterRecognizer.getLetterRecognizer(getContext(),
                     LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE);
             if (mRecognizer == null) {
-                dismissGesturesPopup();
-                mGestures = GESTURES_NONE;
+                setGestures(GESTURES_NONE);
             }
             if (mGestures == GESTURES_FILTER) {
                 mKeyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b97e07b..0a24bb7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -644,6 +644,13 @@
         android:description="@string/permdesc_changeWifiState"
         android:label="@string/permlab_changeWifiState" />
 
+    <!-- Allows applications to enter Wi-Fi Multicast mode -->
+    <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:description="@string/permdesc_changeWifiMulticastState"
+        android:label="@string/permlab_changeWifiMulticastState" />
+
     <!-- Allows applications to discover and pair bluetooth devices -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
diff --git a/core/res/res/raw/latin_lowercase b/core/res/res/raw/latin_lowercase
index 17cfaf0..443d5f8 100644
--- a/core/res/res/raw/latin_lowercase
+++ b/core/res/res/raw/latin_lowercase
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6512006..39485e2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1012,6 +1012,15 @@
       configured Wi-Fi networks.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_changeWifiMulticastState">allow Wi-Fi Multicast
+      reception</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_changeWifiMulticastState">Allows an application to
+      receive packets not directly addressed to your device.  This can be
+      useful when discovering services offered near by.  It uses more power
+      than the non-multicast mode.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetoothAdmin">bluetooth administration</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin">Allows an application to configure
diff --git a/docs/html/shareables/icon_templates-v1.0.zip b/docs/html/shareables/icon_templates-v1.0.zip
index 3e64f9aa..94fbcdc 100644
--- a/docs/html/shareables/icon_templates-v1.0.zip
+++ b/docs/html/shareables/icon_templates-v1.0.zip
Binary files differ
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 30b6733..afad48e 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -55,7 +55,6 @@
 #
 hostSources:= \
 	InetAddress.cpp \
-	Pipe.cpp \
 	Socket.cpp \
 	ZipEntry.cpp \
 	ZipFile.cpp
@@ -71,12 +70,7 @@
 # Use the futex based mutex and condition variable
 # implementation from android-arm because it's shared mem safe
 	LOCAL_SRC_FILES += \
-		futex_synchro.c \
-		executablepath_linux.cpp
-endif
-ifeq ($(HOST_OS),darwin)
-	LOCAL_SRC_FILES += \
-		executablepath_darwin.cpp
+		futex_synchro.c
 endif
 
 LOCAL_MODULE:= libutils
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
deleted file mode 100644
index 613906b..0000000
--- a/libs/utils/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Unidirectional pipe.
-//
-
-#include <utils/Pipe.h>
-#include <utils/Log.h>
-
-#if defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-
-/*
- * Constructor.  Do little.
- */
-Pipe::Pipe(void)
-    : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
-      mWriteHandle(kInvalidHandle)
-{
-}
-
-/*
- * Destructor.  Use the system-appropriate close call.
- */
-Pipe::~Pipe(void)
-{
-#if defined(HAVE_WIN32_IPC)
-    if (mReadHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mReadHandle))
-            LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
-                mReadHandle);
-    }
-    if (mWriteHandle != kInvalidHandle) {
-        FlushFileBuffers((HANDLE)mWriteHandle);
-        if (!CloseHandle((HANDLE)mWriteHandle))
-            LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
-                mWriteHandle);
-    }
-#else
-    if (mReadHandle != kInvalidHandle) {
-        if (close((int) mReadHandle) != 0)
-            LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
-                (int) mReadHandle);
-    }
-    if (mWriteHandle != kInvalidHandle) {
-        if (close((int) mWriteHandle) != 0)
-            LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
-                (int) mWriteHandle);
-    }
-#endif
-}
-
-/*
- * Create the pipe.
- *
- * Use the POSIX stuff for everything but Windows.
- */
-bool Pipe::create(void)
-{
-    assert(mReadHandle == kInvalidHandle);
-    assert(mWriteHandle == kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    /* we use this across processes, so they need to be inheritable */
-    HANDLE handles[2];
-    SECURITY_ATTRIBUTES saAttr;
-
-    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
-    saAttr.bInheritHandle = TRUE;
-    saAttr.lpSecurityDescriptor = NULL;
-
-    if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
-        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
-        return false;
-    }
-    mReadHandle = (unsigned long) handles[0];
-    mWriteHandle = (unsigned long) handles[1];
-    return true;
-#else
-    int fds[2];
-
-    if (pipe(fds) != 0) {
-        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
-        return false;
-    }
-    mReadHandle = fds[0];
-    mWriteHandle = fds[1];
-    return true;
-#endif
-}
-
-/*
- * Create a "half pipe".  Please, no Segway riding.
- */
-bool Pipe::createReader(unsigned long handle)
-{
-    mReadHandle = handle;
-    assert(mWriteHandle == kInvalidHandle);
-    return true;
-}
-
-/*
- * Create a "half pipe" for writing.
- */
-bool Pipe::createWriter(unsigned long handle)
-{
-    mWriteHandle = handle;
-    assert(mReadHandle == kInvalidHandle);
-    return true;
-}
-
-/*
- * Return "true" if create() has been called successfully.
- */
-bool Pipe::isCreated(void)
-{
-    // one or the other should be open
-    return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
-}
-
-
-/*
- * Read data from the pipe.
- *
- * For Linux and Darwin, just call read().  For Windows, implement
- * non-blocking reads by calling PeekNamedPipe first.
- */
-int Pipe::read(void* buf, int count)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD totalBytesAvail = count;
-    DWORD bytesRead;
-
-    if (mReadNonBlocking) {
-        // use PeekNamedPipe to adjust read count expectations
-        if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
-                &totalBytesAvail, NULL))
-        {
-            LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
-            return -1;
-        }
-
-        if (totalBytesAvail == 0)
-            return 0;
-    }
-
-    if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
-            NULL))
-    {
-        DWORD err = GetLastError();
-        if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
-            return 0;
-        LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
-        return -1;
-    }
-
-    return (int) bytesRead;
-#else
-    int cc;
-    cc = ::read(mReadHandle, buf, count);
-    if (cc < 0 && errno == EAGAIN)
-        return 0;
-    return cc;
-#endif
-}
-
-/*
- * Write data to the pipe.
- *
- * POSIX systems are trivial, Windows uses a different call and doesn't
- * handle non-blocking writes.
- *
- * If we add non-blocking support here, we probably want to make it an
- * all-or-nothing write.
- *
- * DO NOT use LOG() here, we could be writing a log message.
- */
-int Pipe::write(const void* buf, int count)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD bytesWritten;
-
-    if (mWriteNonBlocking) {
-        // BUG: can't use PeekNamedPipe() to get the amount of space
-        // left.  Looks like we need to use "overlapped I/O" functions.
-        // I just don't care that much.
-    }
-
-    if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
-        // can't LOG, use stderr
-        fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
-        return -1;
-    }
-
-    return (int) bytesWritten;
-#else
-    int cc;
-    cc = ::write(mWriteHandle, buf, count);
-    if (cc < 0 && errno == EAGAIN)
-        return 0;
-    return cc;
-#endif
-}
-
-/*
- * Figure out if there is data available on the read fd.
- *
- * We return "true" on error because we want the caller to try to read
- * from the pipe.  They'll notice the read failure and do something
- * appropriate.
- */
-bool Pipe::readReady(void)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    DWORD totalBytesAvail;
-
-    if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
-            &totalBytesAvail, NULL))
-    {
-        LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
-        return true;
-    }
-
-    return (totalBytesAvail != 0);
-#else
-    errno = 0;
-    fd_set readfds;
-    struct timeval tv = { 0, 0 };
-    int cc;
-
-    FD_ZERO(&readfds);
-    FD_SET(mReadHandle, &readfds);
-
-    cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
-    if (cc < 0) {
-        LOG(LOG_ERROR, "pipe", "select() failed\n");
-        return true;
-    } else if (cc == 0) {
-        /* timed out, nothing available */
-        return false;
-    } else if (cc == 1) {
-        /* our fd is ready */
-        return true;
-    } else {
-        LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
-        return true;
-    }
-#endif
-}
-
-/*
- * Enable or disable non-blocking mode for the read descriptor.
- *
- * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
- * actually be in non-blocking mode.  If this matters -- i.e. you're not
- * using a select() call -- put a call to readReady() in front of the
- * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
- * Darwin.
- */
-bool Pipe::setReadNonBlocking(bool val)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    // nothing to do
-#else
-    int flags;
-
-    if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
-        LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
-        return false;
-    }
-    if (val)
-        flags |= O_NONBLOCK;
-    else
-        flags &= ~(O_NONBLOCK);
-    if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
-        LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
-        return false;
-    }
-#endif
-
-    mReadNonBlocking = val;
-    return true;
-}
-
-/*
- * Enable or disable non-blocking mode for the write descriptor.
- *
- * As with setReadNonBlocking(), this does not work on the Mac.
- */
-bool Pipe::setWriteNonBlocking(bool val)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
-    // nothing to do
-#else
-    int flags;
-
-    if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
-        LOG(LOG_WARN, "pipe",
-            "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
-            errno);
-        return false;
-    }
-    if (val)
-        flags |= O_NONBLOCK;
-    else
-        flags &= ~(O_NONBLOCK);
-    if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
-        LOG(LOG_WARN, "pipe",
-            "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
-            errno);
-        return false;
-    }
-#endif
-
-    mWriteNonBlocking = val;
-    return true;
-}
-
-/*
- * Specify whether a file descriptor can be inherited by a child process.
- * Under Linux this means setting the close-on-exec flag, under Windows
- * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
- */
-bool Pipe::disallowReadInherit(void)
-{
-    if (mReadHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
-        return false;
-#else
-    if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
-        return false;
-#endif
-    return true;
-}
-bool Pipe::disallowWriteInherit(void)
-{
-    if (mWriteHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
-        return false;
-#else
-    if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
-        return false;
-#endif
-    return true;
-}
-
-/*
- * Close read descriptor.
- */
-bool Pipe::closeRead(void)
-{
-    if (mReadHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (mReadHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mReadHandle)) {
-            LOG(LOG_WARN, "pipe", "failed closing read handle\n");
-            return false;
-        }
-    }
-#else
-    if (mReadHandle != kInvalidHandle) {
-        if (close((int) mReadHandle) != 0) {
-            LOG(LOG_WARN, "pipe", "failed closing read fd\n");
-            return false;
-        }
-    }
-#endif
-    mReadHandle = kInvalidHandle;
-    return true;
-}
-
-/*
- * Close write descriptor.
- */
-bool Pipe::closeWrite(void)
-{
-    if (mWriteHandle == kInvalidHandle)
-        return false;
-
-#if defined(HAVE_WIN32_IPC)
-    if (mWriteHandle != kInvalidHandle) {
-        if (!CloseHandle((HANDLE)mWriteHandle)) {
-            LOG(LOG_WARN, "pipe", "failed closing write handle\n");
-            return false;
-        }
-    }
-#else
-    if (mWriteHandle != kInvalidHandle) {
-        if (close((int) mWriteHandle) != 0) {
-            LOG(LOG_WARN, "pipe", "failed closing write fd\n");
-            return false;
-        }
-    }
-#endif
-    mWriteHandle = kInvalidHandle;
-    return true;
-}
-
-/*
- * Get the read handle.
- */
-unsigned long Pipe::getReadHandle(void)
-{
-    assert(mReadHandle != kInvalidHandle);
-
-    return mReadHandle;
-}
-
-/*
- * Get the write handle.
- */
-unsigned long Pipe::getWriteHandle(void)
-{
-    assert(mWriteHandle != kInvalidHandle);
-
-    return mWriteHandle;
-}
-
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
deleted file mode 100644
index 2e3c3a0..0000000
--- a/libs/utils/executablepath_darwin.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-void executablepath(char s[PATH_MAX])
-{
-    ProcessSerialNumber psn;
-    GetCurrentProcess(&psn);
-    CFDictionaryRef dict;
-    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
-    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
-                CFSTR("CFBundleExecutable"));
-    CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
-}
-
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
deleted file mode 100644
index b8d2a3d..0000000
--- a/libs/utils/executablepath_linux.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void executablepath(char exe[PATH_MAX])
-{
-    char proc[100];
-    sprintf(proc, "/proc/%d/exe", getpid());
-    
-    int err = readlink(proc, exe, PATH_MAX);
-}
-
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 64d1ba2..5bded50 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -588,6 +588,12 @@
 
     }
 
+    private void enforceMulticastChangePermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
+                "WifiService");
+    }
+
     /**
      * see {@link WifiManager#getWifiState()}
      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
@@ -1935,8 +1941,8 @@
         }
     }
 
-    public void enableMulticast(IBinder binder, String tag) {
-        enforceChangePermission();
+    public void acquireMulticastLock(IBinder binder, String tag) {
+        enforceMulticastChangePermission();
 
         synchronized (mMulticasters) {
             mMulticastEnabled++;
@@ -1958,8 +1964,8 @@
         }
     }
 
-    public void disableMulticast() {
-        enforceChangePermission();
+    public void releaseMulticastLock() {
+        enforceMulticastChangePermission();
 
         int uid = Binder.getCallingUid();
         synchronized (mMulticasters) {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0db868e..c31577c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -72,8 +72,8 @@
 
     boolean isMulticastEnabled();
 
-    void enableMulticast(IBinder binder, String tag);
+    void acquireMulticastLock(IBinder binder, String tag);
 
-    void disableMulticast();
+    void releaseMulticastLock();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 141d53f..c4dff6a 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -825,6 +825,117 @@
         return new WifiLock(WIFI_MODE_FULL, tag);
     }
 
+
+    /**
+     * Create a new MulticastLock
+     *
+     * @param tag a tag for the MulticastLock to identify it in debugging
+     *            messages.
+     *
+     * @return a new, unacquired MulticastLock with the given tag.
+     *
+     * @see MulticastLock
+     */
+    public MulticastLock createMulticastLock(String tag) {
+        return new MulticastLock(tag);
+    }
+
+    /**
+     * Allows an application to receive Wifi Multicast packets.
+     * Normally the Wifi stack filters out packets not explicitly
+     * 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
+     */
+    public class MulticastLock {
+        private String mTag;
+        private final IBinder mBinder;
+        private boolean mHeld;
+
+        private MulticastLock(String tag) {
+            mTag = tag;
+            mBinder = new Binder();
+            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.
+         *
+         * Note that other applications may also lock Wifi Multicast on.
+         * Only they can relinquish their lock.
+         *
+         * Also note that applications cannot leave Multicast locked on.
+         * When an app exits or crashes, any Multicast locks will be released.
+         */
+        public void acquire() {
+            synchronized (mBinder) {
+                if (!mHeld) {
+                    try {
+                        mService.acquireMulticastLock(mBinder, mTag);
+                        mHeld = true;
+                    } catch (RemoteException ignore) {
+                    }
+                }
+            }
+        }
+
+        /**
+         * Unlocks Wifi Multicast, restoring the filter of packets
+         * not addressed specifically to this device and saving power.
+         *
+         * 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
+         * the Multicast filter be turned back on.
+         *
+         * Also note that when an app exits or crashes all of its Multicast
+         * Locks will be automatically released.
+         */
+        public void release() {
+            synchronized (mBinder) {
+                if (mHeld) {
+                    try {
+                        mService.releaseMulticastLock();
+                        mHeld = false;
+                    } catch (RemoteException ignore) {
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks whether this MulticastLock is currently held.
+         *
+         * @return true if this MulticastLock is held, false otherwise
+         */
+        public boolean isHeld() {
+            synchronized (mBinder) {
+                return mHeld;
+            }
+        }
+
+        public String toString() {
+            String s1, s2;
+            synchronized (mBinder) {
+                s1 = Integer.toHexString(System.identityHashCode(this));
+                s2 = mHeld ? "held; " : "";
+                return "MulticastLock{ " + s1 + "; " + s2 + " }";
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+            release();
+        }
+    }
+
     /**
      * Check multicast filter status.
      *
@@ -839,50 +950,4 @@
             return false;
         }
     }
-
-    /**
-     * Turn on the reception of multicast packets.
-     * The default behavior is to disable multicast packets as they
-     * have a noticable negative effect on battery life.  An
-     * application can turn them on, but should not leave it on for longer
-     * than needed.  When the app quits (or crashes) its request will
-     * be reverted.
-     *
-     * @param tag a string associated with this request for debugging.
-     *
-     * @return true on success
-     *
-     * @see #disableMulticast
-     *
-     * @hide pending API council approval
-     */
-    public boolean enableMulticast(String tag) {
-        try {
-            mService.enableMulticast(new Binder(), tag);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Return to the default multicast-off setting.
-     * Note that if others had turned on Multicast reception, your
-     * call will not turn it back off - they must also turn off their
-     * request for multicast reception.
-     *
-     * @return true on success
-     *
-     * @see #enableMulticast
-     *
-     * @hide pending API council approval
-     */
-    public boolean disableMulticast() {
-        try {
-            mService.disableMulticast();
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 7ba124fd..e6f4130 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -755,8 +755,10 @@
                  * first and then off.. if nobody else wants it on it'll be
                  * off then and it's all synchronized within the API.
                  */
-                mWM.enableMulticast("WifiStateTracker");
-                mWM.disableMulticast();
+                WifiManager.MulticastLock l = 
+                        mWM.createMulticastLock("WifiStateTracker");
+                l.acquire();
+                l.release();
 
                 if (mBluetoothA2dp == null) {
                     mBluetoothA2dp = new BluetoothA2dp(mContext);