API CHANGE - Add hasGrantedPolicy() API

* Allows an app to detect that it needs to have additional policies granted
* Add "refreshing" parameter to setActiveAdmin() to handle this case
* Minor cleanups to eliminate warnings (mostly for unused things)

Bug: 3253179
Change-Id: I4bf639bf560557130bf98e8cfb75f996fac416f1
diff --git a/api/current.xml b/api/current.xml
index 5cb4c81..a33d30f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -36937,6 +36937,21 @@
 <parameter name="admin" type="android.content.ComponentName">
 </parameter>
 </method>
+<method name="hasGrantedPolicy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="usesPolicy" type="int">
+</parameter>
+</method>
 <method name="isActivePasswordSufficient"
  return="boolean"
  abstract="false"
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f169cd7..1edbdb8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -43,17 +43,12 @@
  */
 public class DevicePolicyManager {
     private static String TAG = "DevicePolicyManager";
-    private static boolean DEBUG = false;
-    private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
 
     private final Context mContext;
     private final IDevicePolicyManager mService;
 
-    private final Handler mHandler;
-
     private DevicePolicyManager(Context context, Handler handler) {
         mContext = context;
-        mHandler = handler;
         mService = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
     }
@@ -74,6 +69,11 @@
      * <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
      * field to provide the user with additional explanation (in addition
      * to your component's description) about what is being added.
+     *
+     * <p>If your administrator is already active, this will ordinarily return immediately (without
+     * user intervention).  However, if your administrator has been updated and is requesting
+     * additional uses-policy flags, the user will be presented with the new list.  New policies
+     * will not be available to the updated administrator until the user has accepted the new list.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_ADD_DEVICE_ADMIN
@@ -179,6 +179,26 @@
     }
 
     /**
+     * Returns true if an administrator has been granted a particular device policy.  This can
+     * be used to check if the administrator was activated under an earlier set of policies,
+     * but requires additional policies after an upgrade.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.  Must be
+     * an active administrator, or an exception will be thrown.
+     * @param usesPolicy Which uses-policy to check, as defined in {@link DeviceAdminInfo}.
+     */
+    public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) {
+        if (mService != null) {
+            try {
+                return mService.hasGrantedPolicy(admin, usesPolicy);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Constant for {@link #setPasswordQuality}: the policy has no requirements
      * for the password.  Note that quality constants are ordered so that higher
      * values are more restrictive.
@@ -1075,10 +1095,10 @@
     /**
      * @hide
      */
-    public void setActiveAdmin(ComponentName policyReceiver) {
+    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
         if (mService != null) {
             try {
-                mService.setActiveAdmin(policyReceiver);
+                mService.setActiveAdmin(policyReceiver, refreshing);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1086,6 +1106,7 @@
     }
 
     /**
+     * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data
      * @hide
      */
     public DeviceAdminInfo getAdminInfo(ComponentName cn) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7acc83e..7504f5b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -75,12 +75,13 @@
     ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
     ComponentName getGlobalProxyAdmin();
     
-    void setActiveAdmin(in ComponentName policyReceiver);
+    void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing);
     boolean isAdminActive(in ComponentName policyReceiver);
     List<ComponentName> getActiveAdmins();
     boolean packageHasActiveAdmins(String packageName);
     void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
     void removeActiveAdmin(in ComponentName policyReceiver);
+    boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy);
     
     void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
         int numbers, int symbols, int nonletter);
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 0dead1c..470af67 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -816,7 +816,11 @@
         }
     }
 
-    public void setActiveAdmin(ComponentName adminReceiver) {
+    /**
+     * @param adminReceiver The admin to add
+     * @param refreshing true = update an active admin, no error
+     */
+    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
@@ -827,15 +831,29 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
+                if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
-                ActiveAdmin admin = new ActiveAdmin(info);
-                mAdminMap.put(adminReceiver, admin);
-                mAdminList.add(admin);
+                ActiveAdmin newAdmin = new ActiveAdmin(info);
+                mAdminMap.put(adminReceiver, newAdmin);
+                int replaceIndex = -1;
+                if (refreshing) {
+                    final int N = mAdminList.size();
+                    for (int i=0; i < N; i++) {
+                        ActiveAdmin oldAdmin = mAdminList.get(i);
+                        if (oldAdmin.info.getComponent().equals(adminReceiver)) {
+                            replaceIndex = i;
+                            break;
+                        }
+                    }
+                }
+                if (replaceIndex == -1) {
+                    mAdminList.add(newAdmin);
+                } else {
+                    mAdminList.set(replaceIndex, newAdmin);
+                }
                 saveSettingsLocked();
-                sendAdminCommandLocked(admin,
-                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
+                sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -848,6 +866,16 @@
         }
     }
 
+    public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
+        synchronized (this) {
+            ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
+            if (administrator == null) {
+                throw new SecurityException("No active admin " + adminReceiver);
+            }
+            return administrator.info.usesPolicy(policyId);
+        }
+    }
+
     public List<ComponentName> getActiveAdmins() {
         synchronized (this) {
             final int N = mAdminList.size();