Merge "Add DO API to get wifi mac address"
diff --git a/api/current.txt b/api/current.txt
index 0263927..0774a9a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5776,6 +5776,7 @@
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
+ method public java.lang.String getWifiMacAddress();
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
diff --git a/api/system-current.txt b/api/system-current.txt
index 621a282..7c2e4be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5906,6 +5906,7 @@
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
+ method public java.lang.String getWifiMacAddress();
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9aac170..471750e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4649,4 +4649,21 @@
return false;
}
}
+
+ /**
+ * Called by device owner to get the MAC address of the Wi-Fi device.
+ *
+ * @return the MAC address of the Wi-Fi device, or null when the information is not
+ * available. (For example, Wi-Fi hasn't been enabled, or the device doesn't support Wi-Fi.)
+ *
+ * <p>The address will be in the {@code XX:XX:XX:XX:XX:XX} format.
+ */
+ public String getWifiMacAddress() {
+ try {
+ return mService.getWifiMacAddress();
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
+ return null;
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e198626..6b4567c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -236,4 +236,5 @@
List<String> getKeepUninstalledPackages(in ComponentName admin);
boolean isManagedProfile(in ComponentName admin);
boolean isSystemOnlyUser(in ComponentName admin);
+ String getWifiMacAddress();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b3b647f..5c3a55d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -71,6 +71,8 @@
import android.net.ConnectivityManager;
import android.net.ProxyInfo;
import android.net.Uri;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
@@ -1121,6 +1123,10 @@
return Looper.myLooper();
}
+ WifiManager getWifiManager() {
+ return mContext.getSystemService(WifiManager.class);
+ }
+
long binderClearCallingIdentity() {
return Binder.clearCallingIdentity();
}
@@ -6871,6 +6877,25 @@
return true;
}
+ @Override
+ public String getWifiMacAddress() {
+ // Make sure caller has DO.
+ synchronized (this) {
+ getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+
+ final long ident = mInjector.binderClearCallingIdentity();
+ try {
+ final WifiInfo wifiInfo = mInjector.getWifiManager().getConnectionInfo();
+ if (wifiInfo == null) {
+ return null;
+ }
+ return wifiInfo.hasRealMacAddress() ? wifiInfo.getMacAddress() : null;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ }
+
/**
* Returns the target sdk version number that the given packageName was built for
* in the given user.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 79ba08d..0159356 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,10 +26,12 @@
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.test.MoreAsserts;
import android.util.Pair;
import org.mockito.ArgumentCaptor;
@@ -1175,4 +1177,64 @@
// TODO Make sure restrictions are written to the file.
}
+
+ public void testGetMacAddress() throws Exception {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+ // In this test, change the caller user to "system".
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ // Make sure admin1 is installed on system user.
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // Test 1. Caller doesn't have DO or DA.
+ try {
+ dpm.getWifiMacAddress();
+ fail();
+ } catch (SecurityException e) {
+ MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ }
+
+ // DO needs to be an DA.
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ assertTrue(dpm.isAdminActive(admin1));
+
+ // Test 2. Caller has DA, but not DO.
+ try {
+ dpm.getWifiMacAddress();
+ fail();
+ } catch (SecurityException e) {
+ MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ }
+
+ // Test 3. Caller has PO, but not DO.
+ assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+ try {
+ dpm.getWifiMacAddress();
+ fail();
+ } catch (SecurityException e) {
+ MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ }
+
+ // Remove PO.
+ dpm.clearProfileOwner(admin1);
+
+ // Test 4, Caller is DO now.
+ assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+ // 4-1. But no WifiInfo.
+ assertNull(dpm.getWifiMacAddress());
+
+ // 4-2. Returns WifiInfo, but with the default MAC.
+ when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
+ assertNull(dpm.getWifiMacAddress());
+
+ // 4-3. With a real MAC address.
+ final WifiInfo wi = new WifiInfo();
+ wi.setMacAddress("11:22:33:44:55:66");
+ when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
+ assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bb1e06d..66d701d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -31,6 +31,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.media.IAudioService;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager.WakeLock;
@@ -217,6 +218,7 @@
public final IBackupManager ibackupManager;
public final IAudioService iaudioService;
public final LockPatternUtils lockPatternUtils;
+ public final WifiManager wifiManager;
public final SettingsForMock settings;
public final MockContentResolver contentResolver;
@@ -249,6 +251,7 @@
ibackupManager = mock(IBackupManager.class);
iaudioService = mock(IAudioService.class);
lockPatternUtils = mock(LockPatternUtils.class);
+ wifiManager = mock(WifiManager.class);
settings = mock(SettingsForMock.class);
// Package manager is huge, so we use a partial mock instead.
@@ -303,6 +306,8 @@
return userManager;
case Context.POWER_SERVICE:
return powerManager;
+ case Context.WIFI_SERVICE:
+ return wifiManager;
}
throw new UnsupportedOperationException();
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index e25b38c..9f8af6e 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -424,6 +424,15 @@
return mMacAddress;
}
+ /**
+ * @return true if {@link #getMacAddress()} has a real MAC address.
+ *
+ * @hide
+ */
+ public boolean hasRealMacAddress() {
+ return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress);
+ }
+
/** {@hide} */
public void setMeteredHint(boolean meteredHint) {
mMeteredHint = meteredHint;