diff --git a/api/current.xml b/api/current.xml
index ce1b7269428bc..bf3044e30fce3 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -309,6 +309,17 @@
visibility="public"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ allow Wi-Fi Multicast
+ reception
+
+ 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.
+
bluetooth administration
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5fa8701fda050..1528ba34efc72 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -588,6 +588,12 @@ public class WifiService extends IWifiManager.Stub {
}
+ 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},
@@ -1930,8 +1936,8 @@ public class WifiService extends IWifiManager.Stub {
}
}
- public void enableMulticast(IBinder binder, String tag) {
- enforceChangePermission();
+ public void acquireMulticastLock(IBinder binder, String tag) {
+ enforceMulticastChangePermission();
synchronized (mMulticasters) {
mMulticastEnabled++;
@@ -1953,8 +1959,8 @@ public class WifiService extends IWifiManager.Stub {
}
}
- 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 7c3af69341e5b..3d65d3c66f388 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -72,8 +72,8 @@ interface IWifiManager
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 1a7caef187983..5b8ced67662cf 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -824,6 +824,117 @@ public class WifiManager {
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.
*
@@ -838,50 +949,4 @@ public class WifiManager {
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 6771136ee3793..2fbc779503589 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -747,8 +747,10 @@ public class WifiStateTracker extends NetworkStateTracker {
* 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);