Merge "Don't trigger click if long press already happened"
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..fbc60cd 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[]);
@@ -33054,6 +33055,7 @@
 
   public class TelecomManager {
     method public void acceptRingingCall();
+    method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void addNewUnknownCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1c65c94..471750e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -89,6 +89,10 @@
     private final Context mContext;
     private final IDevicePolicyManager mService;
 
+    // TODO Use it everywhere.
+    private static final String REMOTE_EXCEPTION_MESSAGE =
+            "Failed to talk with device policy manager service";
+
     private DevicePolicyManager(Context context) {
         this(context, IDevicePolicyManager.Stub.asInterface(
                         ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
@@ -686,7 +690,7 @@
      * extra field. This will invoke a UI to bring the user through adding the profile owner admin
      * to remotely control restrictions on the user.
      *
-     * <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
+     * <p>The intent must be invoked via {@link Activity#startActivityForResult} to receive the
      * result of whether or not the user approved the action. If approved, the result will
      * be {@link Activity#RESULT_OK} and the component will be set as an active admin as well
      * as a profile owner.
@@ -2765,37 +2769,94 @@
      * the setup process.
      * @param packageName the package name of the app, to compare with the registered device owner
      * app, if any.
-     * @return whether or not the package is registered as the device owner app.  Note this method
-     * does *not* check weather the device owner is actually running on the current user.
+     * @return whether or not the package is registered as the device owner app.
      */
     public boolean isDeviceOwnerApp(String packageName) {
+        return isDeviceOwnerAppOnCallingUser(packageName);
+    }
+
+    /**
+     * @return true if a package is registered as device owner, only when it's running on the
+     * calling user.
+     *
+     * <p>Same as {@link #isDeviceOwnerApp}, but bundled code should use it for clarity.
+     * @hide
+     */
+    public boolean isDeviceOwnerAppOnCallingUser(String packageName) {
+        return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ true);
+    }
+
+    /**
+     * @return true if a package is registered as device owner, even if it's running on a different
+     * user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public boolean isDeviceOwnerAppOnAnyUser(String packageName) {
+        return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ false);
+    }
+
+    /**
+     * @return device owner component name, only when it's running on the calling user.
+     *
+     * @hide
+     */
+    public ComponentName getDeviceOwnerComponentOnCallingUser() {
+        return getDeviceOwnerComponentInner(/* callingUserOnly =*/ true);
+    }
+
+    /**
+     * @return device owner component name, even if it's running on a different user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public ComponentName getDeviceOwnerComponentOnAnyUser() {
+        return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
+    }
+
+    private boolean isDeviceOwnerAppOnAnyUserInner(String packageName, boolean callingUserOnly) {
         if (packageName == null) {
             return false;
         }
-        final ComponentName deviceOwner = getDeviceOwnerComponent();
+        final ComponentName deviceOwner = getDeviceOwnerComponentInner(callingUserOnly);
         if (deviceOwner == null) {
             return false;
         }
         return packageName.equals(deviceOwner.getPackageName());
     }
 
-    /**
-     * @hide
-     * Redirect to isDeviceOwnerApp.
-     */
-    public boolean isDeviceOwner(String packageName) {
-        return isDeviceOwnerApp(packageName);
+    private ComponentName getDeviceOwnerComponentInner(boolean callingUserOnly) {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerComponent(callingUserOnly);
+            } catch (RemoteException re) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            }
+        }
+        return null;
     }
 
     /**
-     * Check whether a given component is registered as a device owner.
-     * Note this method does *not* check weather the device owner is actually running on the current
-     * user.
+     * @return ID of the user who runs device owner, or {@link UserHandle#USER_NULL} if there's
+     * no device owner.
+     *
+     * <p>Requires the MANAGE_USERS permission.
      *
      * @hide
      */
-    public boolean isDeviceOwner(ComponentName who) {
-        return (who != null) && who.equals(getDeviceOwner());
+    public int getDeviceOwnerUserId() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerUserId();
+            } catch (RemoteException re) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            }
+        }
+        return UserHandle.USER_NULL;
     }
 
     /**
@@ -2818,46 +2879,43 @@
     }
 
     /**
-     * Returns the device owner package name.  Note this method will still return the device owner
-     * package name even if it's running on a different user.
+     * Returns the device owner package name, only if it's running on the calling user.
+     *
+     * <p>Bundled components should use {@code getDeviceOwnerComponentOnCallingUser()} for clarity.
      *
      * @hide
      */
     @SystemApi
     public String getDeviceOwner() {
-        final ComponentName componentName = getDeviceOwnerComponent();
-        return componentName == null ? null : componentName.getPackageName();
+        final ComponentName name = getDeviceOwnerComponentOnCallingUser();
+        return name != null ? name.getPackageName() : null;
     }
 
     /**
-     * Returns the device owner name.  Note this method will still return the device owner
-     * name even if it's running on a different user.
+     * @return true if the device is managed by any device owner.
+     *
+     * <p>Requires the MANAGE_USERS permission.
      *
      * @hide
      */
-    public String getDeviceOwnerName() {
+    public boolean isDeviceManaged() {
+        return getDeviceOwnerComponentOnAnyUser() != null;
+    }
+
+    /**
+     * Returns the device owner name.  Note this method *will* return the device owner
+     * name when it's running on a different user.
+     *
+     * <p>Requires the MANAGE_USERS permission.
+     *
+     * @hide
+     */
+    public String getDeviceOwnerNameOnAnyUser() {
         if (mService != null) {
             try {
                 return mService.getDeviceOwnerName();
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get device owner");
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the device owner component name.  Note this method will still return the device owner
-     * component name even if it's running on a different user.
-     *
-     * @hide
-     */
-    public ComponentName getDeviceOwnerComponent() {
-        if (mService != null) {
-            try {
-                return mService.getDeviceOwner();
-            } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get device owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
             }
         }
         return null;
@@ -3130,7 +3188,7 @@
 
     /**
      * @hide
-     * @param user The user for whom to fetch the profile owner name, if any.
+     * @param userId The user for whom to fetch the profile owner name, if any.
      * @return the human readable name of the organisation associated with this profile owner or
      *         null if one is not set.
      * @throws IllegalArgumentException if the userId is invalid.
@@ -4591,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 fc7c2b3..6b4567c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -114,9 +114,10 @@
     void reportSuccessfulPasswordAttempt(int userHandle);
 
     boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
-    ComponentName getDeviceOwner();
+    ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
     String getDeviceOwnerName();
     void clearDeviceOwner(String packageName);
+    int getDeviceOwnerUserId();
 
     boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
     ComponentName getProfileOwner(int userHandle);
@@ -235,4 +236,5 @@
     List<String> getKeepUninstalledPackages(in ComponentName admin);
     boolean isManagedProfile(in ComponentName admin);
     boolean isSystemOnlyUser(in ComponentName admin);
+    String getWifiMacAddress();
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e758835..67e170f 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -336,8 +336,8 @@
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
+    public void onStart() {
+        super.onStart();
         if (mState != STATE_INITIALIZING && mCurrentPrinter != null) {
             mPrinterRegistry.setTrackedPrinter(mCurrentPrinter.getId());
         }
@@ -379,10 +379,15 @@
             }
         }
 
+        super.onPause();
+    }
+
+    @Override
+    protected void onStop() {
         mPrinterAvailabilityDetector.cancel();
         mPrinterRegistry.setTrackedPrinter(null);
 
-        super.onPause();
+        super.onStop();
     }
 
     @Override
@@ -973,7 +978,7 @@
         if (newFragment != null) {
             transaction.add(R.id.embedded_content_container, newFragment, FRAGMENT_TAG);
         }
-        transaction.commit();
+        transaction.commitAllowingStateLoss();
         getFragmentManager().executePendingTransactions();
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3971706..fbf8a2bd9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -54,7 +54,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -70,7 +69,6 @@
 import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -148,22 +146,6 @@
 
     private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
 
-    // Per user settings that cannot be modified if associated user restrictions are enabled.
-    private static final Map<String, String> sSettingToUserRestrictionMap = new ArrayMap<>();
-    static {
-        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_MODE,
-                UserManager.DISALLOW_SHARE_LOCATION);
-        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                UserManager.DISALLOW_SHARE_LOCATION);
-        sSettingToUserRestrictionMap.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
-                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-        sSettingToUserRestrictionMap.put(Settings.Global.ADB_ENABLED,
-                UserManager.DISALLOW_DEBUGGING_FEATURES);
-        sSettingToUserRestrictionMap.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                UserManager.ENSURE_VERIFY_APPS);
-        sSettingToUserRestrictionMap.put(Settings.Global.PREFERRED_NETWORK_MODE,
-                UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-    }
 
     // Per user secure settings that moved to the for all users global settings.
     static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
@@ -647,8 +629,9 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
-        // If this is a setting that is currently restricted for this user, done.
-        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+        // If this is a setting that is currently restricted for this user, do not allow
+        // unrestricting changes.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
             return false;
         }
 
@@ -772,8 +755,9 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
-        // If this is a setting that is currently restricted for this user, done.
-        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+        // If this is a setting that is currently restricted for this user, do not allow
+        // unrestricting changes.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
             return false;
         }
 
@@ -978,12 +962,59 @@
         return false;
     }
 
-    private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId) {
-        String restriction = sSettingToUserRestrictionMap.get(setting);
-        if (restriction == null) {
-            return false;
+    /**
+     * Checks whether changing a setting to a value is prohibited by the corresponding user
+     * restriction.
+     *
+     * <p>See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestrictionLR},
+     * which should be in sync with this method.
+     *
+     * @return true if the change is prohibited, false if the change is allowed.
+     */
+    private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
+            String value) {
+        String restriction;
+        switch (setting) {
+            case Settings.Secure.LOCATION_MODE:
+                // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
+                // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come
+                // here normally, but we still protect it here from a direct provider write.
+                if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) return false;
+                restriction = UserManager.DISALLOW_SHARE_LOCATION;
+                break;
+
+            case Settings.Secure.LOCATION_PROVIDERS_ALLOWED:
+                // See SettingsProvider.updateLocationProvidersAllowedLocked.  "-" is to disable
+                // a provider, which should be allowed even if the user restriction is set.
+                if (value != null && value.startsWith("-")) return false;
+                restriction = UserManager.DISALLOW_SHARE_LOCATION;
+                break;
+
+            case Settings.Secure.INSTALL_NON_MARKET_APPS:
+                if ("0".equals(value)) return false;
+                restriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
+                break;
+
+            case Settings.Global.ADB_ENABLED:
+                if ("0".equals(value)) return false;
+                restriction = UserManager.DISALLOW_DEBUGGING_FEATURES;
+                break;
+
+            case Settings.Global.PACKAGE_VERIFIER_ENABLE:
+            case Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB:
+                if ("1".equals(value)) return false;
+                restriction = UserManager.ENSURE_VERIFY_APPS;
+                break;
+
+            case Settings.Global.PREFERRED_NETWORK_MODE:
+                restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
+                break;
+
+            default:
+                return false;
         }
-        return mUserManager.hasUserRestriction(restriction, new UserHandle(userId));
+
+        return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
     }
 
     private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
@@ -1094,6 +1125,9 @@
      * But helper functions in android.providers.Settings can enable or disable
      * a single provider by using a "+" or "-" prefix before the provider name.
      *
+     * <p>See also {@link #isGlobalOrSecureSettingRestrictedForUser()}.  If DISALLOW_SHARE_LOCATION
+     * is set, the said method will only allow values with the "-" prefix.
+     *
      * @returns whether the enabled location providers changed.
      */
     private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 47189b0..6d8b476 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -111,7 +111,9 @@
 
     private void handleRefreshState() {
         mIsIconVisible = mSecurityController.isVpnEnabled();
-        if (mSecurityController.hasDeviceOwner()) {
+        // If the device has device owner, show "Device may be monitored", but --
+        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
+        if (mSecurityController.isDeviceManaged()) {
             mFooterTextId = R.string.device_owned_footer;
             mIsVisible = true;
         } else {
@@ -156,6 +158,8 @@
 
     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
             String profileVpn, boolean primaryUserIsManaged) {
+        // Show a special warning when the device has device owner, but --
+        // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
         if (deviceOwner != null) {
             if (primaryVpn != null) {
                 return mContext.getString(R.string.monitoring_description_vpn_app_device_owned,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index f06e5d3..a22f988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -16,8 +16,8 @@
 package com.android.systemui.statusbar.policy;
 
 public interface SecurityController {
-
-    boolean hasDeviceOwner();
+    /** Whether the device has device owner, even if not on this user. */
+    boolean isDeviceManaged();
     boolean hasProfileOwner();
     String getDeviceOwnerName();
     String getProfileOwnerName();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 88f028f..6ddd7a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -102,13 +102,13 @@
     }
 
     @Override
-    public boolean hasDeviceOwner() {
-        return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner());
+    public boolean isDeviceManaged() {
+        return mDevicePolicyManager.isDeviceManaged();
     }
 
     @Override
     public String getDeviceOwnerName() {
-        return mDevicePolicyManager.getDeviceOwnerName();
+        return mDevicePolicyManager.getDeviceOwnerNameOnAnyUser();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index cf09b84..5d1906c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -866,10 +866,11 @@
             mAppOps.checkPackage(callingUid, callerPackageName);
         }
 
-        // Check whether the caller is device owner
+        // Check whether the caller is device owner, in which case we do it silently.
         DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
-        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName);
+        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
+                callerPackageName);
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                 statusReceiver, packageName, isDeviceOwner, userId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b0e43a5..fa0aa37 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -228,7 +228,8 @@
         final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
         final boolean forcePermissionPrompt =
                 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
-        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
+        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
+                installerPackageName);
         if ((isPermissionGranted
                         || isInstallerRoot
                         || mIsInstallerDeviceOwner)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 21a4206..4bc79cb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13065,7 +13065,8 @@
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
             if (dpm != null) {
-                final ComponentName deviceOwnerComponentName = dpm.getDeviceOwner();
+                final ComponentName deviceOwnerComponentName = dpm.getDeviceOwnerComponent(
+                        /* callingUserOnly =*/ false);
                 final String deviceOwnerPackageName = deviceOwnerComponentName == null ? null
                         : deviceOwnerComponentName.getPackageName();
                 // Does the package contains the device owner?
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 558ea58..ff829ff 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -513,7 +513,7 @@
         DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         // restricted profile can be created if there is no DO set and the admin user has no PO
-        return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
+        return !dpm.isDeviceManaged() && dpm.getProfileOwnerAsUser(userId) == null;
     }
 
     /*
@@ -1599,7 +1599,7 @@
                     DevicePolicyManager devicePolicyManager = (DevicePolicyManager)
                             mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
                     if (devicePolicyManager == null
-                            || devicePolicyManager.getDeviceOwner() == null) {
+                            || !devicePolicyManager.isDeviceManaged()) {
                         flags |= UserInfo.FLAG_ADMIN;
                     }
                 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 85453a8..77abd3e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -285,6 +285,10 @@
      * <p>Note this method is called by {@link UserManagerService} while holding
      * {@code mRestrictionLock}. Be aware when calling into other services, which could cause
      * a deadlock.
+     *
+     * <p>See also {@link
+     * com.android.providers.settings.SettingsProvider#isGlobalOrSecureSettingRestrictedForUser},
+     * which should be in sync with this method.
      */
     private static void applyUserRestrictionLR(Context context, int userId, String key,
             boolean newValue) {
@@ -306,7 +310,7 @@
                 case UserManager.DISALLOW_CONFIG_WIFI:
                     if (newValue) {
                         android.provider.Settings.Secure.putIntForUser(cr,
-                                android.provider.Settings.Secure
+                                android.provider.Settings.Global
                                         .WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userId);
                     }
                     break;
@@ -316,9 +320,6 @@
                                 android.provider.Settings.Secure.LOCATION_MODE,
                                 android.provider.Settings.Secure.LOCATION_MODE_OFF,
                                 userId);
-                        android.provider.Settings.Secure.putStringForUser(cr,
-                                android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
-                                userId);
                     }
                     // Send out notifications as some clients may want to reread the
                     // value which actually changed due to a restriction having been
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8beee73..f80a611 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -71,8 +71,11 @@
 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.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -1121,6 +1124,10 @@
             return Looper.myLooper();
         }
 
+        WifiManager getWifiManager() {
+            return mContext.getSystemService(WifiManager.class);
+        }
+
         long binderClearCallingIdentity() {
             return Binder.clearCallingIdentity();
         }
@@ -1715,7 +1722,8 @@
         }
     }
 
-    public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+    public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
+            boolean throwForMissiongPermission) {
         if (!mHasFeature) {
             return null;
         }
@@ -1730,8 +1738,20 @@
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
 
+        final ResolveInfo ri = infos.get(0);
+
+        if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
+            final String message = "DeviceAdminReceiver " + adminName + " must be protected with"
+                    + permission.BIND_DEVICE_ADMIN;
+            Slog.w(LOG_TAG, message);
+            if (throwForMissiongPermission &&
+                    ri.activityInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
+                throw new IllegalArgumentException(message);
+            }
+        }
+
         try {
-            return new DeviceAdminInfo(mContext, infos.get(0));
+            return new DeviceAdminInfo(mContext, ri);
         } catch (XmlPullParserException e) {
             Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
                     e);
@@ -1922,7 +1942,8 @@
                     String name = parser.getAttributeValue(null, "name");
                     try {
                         DeviceAdminInfo dai = findAdmin(
-                                ComponentName.unflattenFromString(name), userHandle);
+                                ComponentName.unflattenFromString(name), userHandle,
+                                /* throwForMissionPermission= */ false);
                         if (VERBOSE_LOG
                                 && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
                                 != userHandle)) {
@@ -2045,9 +2066,12 @@
     private void updateDeviceOwnerLocked() {
         long ident = mInjector.binderClearCallingIdentity();
         try {
-            if (getDeviceOwner() != null) {
+            // TODO This is to prevent DO from getting "clear data"ed, but it should also check the
+            // user id and also protect all other DAs too.
+            final ComponentName deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
+            if (deviceOwnerComponent != null) {
                 mInjector.getIActivityManager()
-                        .updateDeviceOwner(getDeviceOwner().getPackageName());
+                        .updateDeviceOwner(deviceOwnerComponent.getPackageName());
             }
         } catch (RemoteException e) {
             // Not gonna happen.
@@ -2248,6 +2272,7 @@
             // Build and show a warning notification
             int smallIconId;
             String contentText;
+            // TODO Why does it use the DO name?  The cert APIs are all for PO. b/25772443
             final String ownerName = getDeviceOwnerName();
             if (isManagedProfile(userHandle.getIdentifier())) {
                 contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_administrator);
@@ -2309,7 +2334,8 @@
         enforceCrossUserPermission(userHandle);
 
         DevicePolicyData policy = getUserData(userHandle);
-        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
+        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
+                /* throwForMissionPermission= */ true);
         if (info == null) {
             throw new IllegalArgumentException("Bad admin: " + adminReceiver);
         }
@@ -4600,22 +4626,46 @@
     }
 
     @Override
-    public ComponentName getDeviceOwner() {
+    public ComponentName getDeviceOwnerComponent(boolean callingUserOnly) {
         if (!mHasFeature) {
             return null;
         }
+        if (!callingUserOnly) {
+            enforceManageUsers();
+        }
         synchronized (this) {
+            if (!mOwners.hasDeviceOwner()) {
+                return null;
+            }
+            if (callingUserOnly && mInjector.userHandleGetCallingUserId() !=
+                    mOwners.getDeviceOwnerUserId()) {
+                return null;
+            }
             return mOwners.getDeviceOwnerComponent();
         }
     }
 
     @Override
+    public int getDeviceOwnerUserId() {
+        if (!mHasFeature) {
+            return UserHandle.USER_NULL;
+        }
+        enforceManageUsers();
+        synchronized (this) {
+            return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
+        }
+    }
+
+    /**
+     * Returns the "name" of the device owner.  It'll work for non-DO users too, but requires
+     * MANAGE_USERS.
+     */
+    @Override
     public String getDeviceOwnerName() {
         if (!mHasFeature) {
             return null;
         }
-        // TODO: Do we really need it?  getDeviceOwner() doesn't require it.
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        enforceManageUsers();
         synchronized (this) {
             if (!mOwners.hasDeviceOwner()) {
                 return null;
@@ -4630,7 +4680,7 @@
     // Returns the active device owner or null if there is no device owner.
     @VisibleForTesting
     ActiveAdmin getDeviceOwnerAdminLocked() {
-        ComponentName component = getDeviceOwner();
+        ComponentName component = mOwners.getDeviceOwnerComponent();
         if (component == null) {
             return null;
         }
@@ -4659,16 +4709,20 @@
         } catch (NameNotFoundException e) {
             throw new SecurityException(e);
         }
-        if (!mOwners.hasDeviceOwner() || !getDeviceOwner().getPackageName().equals(packageName)
-                || (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
-            throw new SecurityException("clearDeviceOwner can only be called by the device owner");
-        }
         synchronized (this) {
+            if (!mOwners.hasDeviceOwner()
+                    || !mOwners.getDeviceOwnerComponent().getPackageName().equals(packageName)
+                    || (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
+                throw new SecurityException(
+                        "clearDeviceOwner can only be called by the device owner");
+            }
+
             final ActiveAdmin admin = getDeviceOwnerAdminLocked();
             if (admin != null) {
                 admin.disableCamera = false;
                 admin.userRestrictions = null;
             }
+
             clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
 
             mOwners.clearDeviceOwner();
@@ -4857,7 +4911,7 @@
         if (!mHasFeature) {
             return null;
         }
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        enforceManageUsers();
         ComponentName profileOwner = getProfileOwner(userHandle);
         if (profileOwner == null) {
             return null;
@@ -4987,13 +5041,20 @@
         }
     }
 
+    private void enforceManageUsers() {
+        final int callingUid = mInjector.binderGetCallingUid();
+        if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        }
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
         }
         final int callingUid = mInjector.binderGetCallingUid();
         if (userHandle == UserHandle.getUserId(callingUid)) return;
-        if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+        if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
                     + " INTERACT_ACROSS_USERS_FULL permission");
@@ -6619,8 +6680,9 @@
                 updateReceivedTime);
 
         synchronized (this) {
-            final String deviceOwnerPackage = getDeviceOwner() == null ? null :
-                    getDeviceOwner().getPackageName();
+            final String deviceOwnerPackage =
+                    mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerComponent().getPackageName()
+                            : null;
             if (deviceOwnerPackage == null) {
                 return;
             }
@@ -6831,6 +6893,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/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index f37bb9eb..6a50a6e 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -343,9 +343,7 @@
     public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
-            if (mActiveServices.isEmpty()) {
-                return;
-            }
+
             if (mPrinterDiscoverySession == null) {
                 // If we do not have a session, tell all service to create one.
                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index c147bcc..eed326e 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -94,6 +94,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$AdminNoPerm">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
     </application>
 
     <instrumentation
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 0bd4896..565ef4b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,15 +26,21 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
+import android.net.wifi.WifiInfo;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
 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;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,9 +62,9 @@
  *
  m FrameworksServicesTests &&
  adb install \
- -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
  adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
@@ -81,6 +87,7 @@
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
+        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID);
 
         setUpUserManager();
     }
@@ -334,6 +341,33 @@
 
     /**
      * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with
+     * BIND_DEVICE_ADMIN.
+     */
+    public void testSetActiveAdmin_permissionCheck() throws Exception {
+        // 1. Make sure the caller has proper permissions.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        try {
+            dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            assertTrue(expected.getMessage().contains(permission.BIND_DEVICE_ADMIN));
+        }
+        assertFalse(dpm.isAdminActive(adminNoPerm));
+
+        // Change the target API level to MNC.  Now it can be set as DA.
+        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null,
+                VERSION_CODES.M);
+        dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(adminNoPerm));
+
+        // TODO Test the "load from the file" case where DA will still be loaded even without
+        // BIND_DEVICE_ADMIN and target API is N.
+    }
+
+    /**
+     * Test for:
      * {@link DevicePolicyManager#removeActiveAdmin}
      */
     public void testRemoveActiveAdmin_SecurityException() {
@@ -458,6 +492,7 @@
      */
     public void testSetDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -467,12 +502,29 @@
         // Make sure admin1 is installed on system user.
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
 
+        // Check various get APIs.
+        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
+
         // DO needs to be an DA.
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
 
         // Fire!
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
 
+        // getDeviceOwnerComponent should return the admin1 component.
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+        // Check various get APIs.
+        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
+
+        // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
         // Verify internal calls.
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
@@ -485,7 +537,7 @@
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Try to set a profile owner on the same user, which should fail.
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -502,11 +554,163 @@
         // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
     }
 
+    private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
+        final int origCallingUser = mContext.binder.callingUid;
+        final List origPermissions = new ArrayList(mContext.callerPermissions);
+        mContext.callerPermissions.clear();
+
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
+
+        mContext.binder.callingUid = Process.SYSTEM_UID;
+
+        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
+        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        // Still with MANAGE_USERS.
+        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = Process.SYSTEM_UID;
+        mContext.callerPermissions.remove(permission.MANAGE_USERS);
+        // System can still call "OnAnyUser" without MANAGE_USERS.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        // Still no MANAGE_USERS.
+        if (hasDeviceOwner) {
+            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+        } else {
+            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+        }
+
+        try {
+            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerComponentOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerUserId();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerNameOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        // Still no MANAGE_USERS.
+        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+        try {
+            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerComponentOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerUserId();
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            dpm.getDeviceOwnerNameOnAnyUser();
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        // Restore.
+        mContext.binder.callingUid = origCallingUser;
+        mContext.callerPermissions.addAll(origPermissions);
+    }
+
+
     /**
      * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
      */
     public void testSetDeviceOwner_noSuchPackage() {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -528,6 +732,7 @@
 
     public void testClearDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -547,7 +752,7 @@
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Set up other mocks.
         when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
@@ -559,13 +764,14 @@
         dpm.clearDeviceOwnerApp(admin1.getPackageName());
 
         // Now DO shouldn't be set.
-        assertNull(dpm.getDeviceOwner());
+        assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
 
         // TODO Check other calls.
     }
 
     public void testClearDeviceOwner_fromDifferentUser() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -585,7 +791,7 @@
         verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
-        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
 
         // Now call clear from the secondary user, which should throw.
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -601,8 +807,8 @@
             assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
         }
 
-        // Now DO shouldn't be set.
-        assertNotNull(dpm.getDeviceOwner());
+        // DO shouldn't be removed.
+        assertTrue(dpm.isDeviceManaged());
     }
 
     public void testSetProfileOwner() throws Exception {
@@ -639,6 +845,7 @@
         mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
 
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -667,8 +874,7 @@
         mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
         assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
 
-        // Make sure it's set.
-        assertEquals(admin2, dpm.getDeviceOwnerComponent());
+        assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
 
         // Then check getDeviceOwnerAdminLocked().
         assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
@@ -692,7 +898,7 @@
         dpms.mOwners.writeDeviceOwner();
 
         // Make sure the DO component name doesn't have a class name.
-        assertEquals("", dpms.getDeviceOwner().getClassName());
+        assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
 
         // Then create a new DPMS to have it load the settings from files.
         when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
@@ -702,7 +908,7 @@
         // Now the DO component name is a full name.
         // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
         // DO.
-        assertEquals(admin1, dpms.getDeviceOwner());
+        assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
     }
 
     public void testSetGetApplicationRestriction() {
@@ -740,6 +946,7 @@
 
     public void testSetUserRestriction_asDo() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
 
@@ -1000,4 +1207,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/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index e11f3fb..5b33e4d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -43,6 +43,7 @@
     public ComponentName admin1;
     public ComponentName admin2;
     public ComponentName admin3;
+    public ComponentName adminNoPerm;
 
     @Override
     protected void setUp() throws Exception {
@@ -56,6 +57,7 @@
         admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
         admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
         admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+        adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
     }
 
     @Override
@@ -67,11 +69,36 @@
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
             throws Exception {
         setUpPackageManagerForAdmin(admin, packageUid,
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+                /* enabledSetting =*/ null, /* appTargetSdk = */ null);
     }
 
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
             int enabledSetting) throws Exception {
+        setUpPackageManagerForAdmin(admin, packageUid, enabledSetting, /* appTargetSdk = */ null);
+    }
+
+    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
+            Integer enabledSetting, Integer appTargetSdk) throws Exception {
+
+        // Set up getApplicationInfo().
+
+        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
+                mRealTestContext.getPackageManager().getApplicationInfo(
+                        admin.getPackageName(),
+                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
+
+        ai.enabledSetting = enabledSetting == null
+                ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                : enabledSetting;
+        if (appTargetSdk != null) {
+            ai.targetSdkVersion = appTargetSdk;
+        }
+        ai.uid = packageUid;
+
+        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
+                eq(admin.getPackageName()),
+                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(UserHandle.getUserId(packageUid)));
 
         // Set up queryBroadcastReceivers().
 
@@ -88,7 +115,7 @@
         realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
 
         // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid;
+        realResolveInfo.get(0).activityInfo.applicationInfo = ai;
 
         doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
                 MockUtils.checkIntentComponent(admin),
@@ -96,21 +123,6 @@
                         | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
                 eq(UserHandle.getUserId(packageUid)));
 
-        // Set up getApplicationInfo().
-
-        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
-                mRealTestContext.getPackageManager().getApplicationInfo(
-                        admin.getPackageName(),
-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
-
-        ai.enabledSetting = enabledSetting;
-        ai.uid = packageUid;
-
-        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
-                eq(admin.getPackageName()),
-                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(UserHandle.getUserId(packageUid)));
-
         // Set up getPackageInfo().
 
         final PackageInfo pi = DpmTestUtils.cloneParcelable(
@@ -118,7 +130,7 @@
                         admin.getPackageName(), 0));
         assertTrue(pi.applicationInfo.flags != 0);
 
-        pi.applicationInfo.uid = packageUid;
+        pi.applicationInfo = ai;
 
         doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
                 eq(admin.getPackageName()),
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
index 08293a2..a0f4d97 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
@@ -24,4 +24,6 @@
     }
     public static class Admin3 extends DeviceAdminReceiver {
     }
+    public static class AdminNoPerm extends DeviceAdminReceiver {
+    }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8b347cc..b5b4e5f 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1051,7 +1051,9 @@
      * If there is a ringing incoming call, this method accepts the call on behalf of the user.
      * TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
      * this method (clockwork & gearhead).
-     *
+     * If the incoming call is a video call, the call will be answered with the same video state as
+     * the incoming call requests.  This means, for example, that an incoming call requesting
+     * {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
      * @hide
      */
     @SystemApi
@@ -1066,6 +1068,24 @@
     }
 
     /**
+     * If there is a ringing incoming call, this method accepts the call on behalf of the user,
+     * with the specified video state.
+     *
+     * @param videoState The desired video state to answer the call with.
+     * @hide
+     */
+    @SystemApi
+    public void acceptRingingCall(int videoState) {
+        try {
+            if (isServiceConnected()) {
+                getTelecomService().acceptRingingCallWithVideoState(videoState);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecomService#acceptRingingCallWithVideoState", e);
+        }
+    }
+
+    /**
      * Silences the ringer if a ringing call exists.
      *
      * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 2e07759..856e210 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -178,6 +178,11 @@
     void acceptRingingCall();
 
     /**
+     * @see TelecomServiceImpl#acceptRingingCallWithVideoState(int)
+     */
+    void acceptRingingCallWithVideoState(int videoState);
+
+    /**
      * @see TelecomServiceImpl#cancelMissedCallsNotification
      */
     void cancelMissedCallsNotification(String callingPackage);
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index ef39a6c..4785169 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -1012,7 +1012,7 @@
      *
      * @param tables the new list of enabled single shift tables
      */
-    static synchronized void setEnabledSingleShiftTables(int[] tables) {
+    public static synchronized void setEnabledSingleShiftTables(int[] tables) {
         sEnabledSingleShiftTables = tables;
         sDisableCountryEncodingCheck = true;
 
@@ -1030,7 +1030,7 @@
      *
      * @param tables the new list of enabled locking shift tables
      */
-    static synchronized void setEnabledLockingShiftTables(int[] tables) {
+    public static synchronized void setEnabledLockingShiftTables(int[] tables) {
         sEnabledLockingShiftTables = tables;
         sDisableCountryEncodingCheck = true;
     }
@@ -1042,7 +1042,7 @@
      *
      * @return the list of enabled single shift tables
      */
-    static synchronized int[] getEnabledSingleShiftTables() {
+    public static synchronized int[] getEnabledSingleShiftTables() {
         return sEnabledSingleShiftTables;
     }
 
@@ -1053,7 +1053,7 @@
      *
      * @return the list of enabled locking shift tables
      */
-    static synchronized int[] getEnabledLockingShiftTables() {
+    public static synchronized int[] getEnabledLockingShiftTables() {
         return sEnabledLockingShiftTables;
     }
 
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;