Merge "Add Device/Profile Owner gated apis for setting/getting blocked packages."
diff --git a/api/current.txt b/api/current.txt
index 3a713cc..96d6cc3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5096,6 +5096,7 @@
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(android.content.ComponentName);
     method public boolean isProfileOwnerApp(java.lang.String);
@@ -5103,7 +5104,9 @@
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
     method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setApplicationBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
+    method public int setApplicationsBlocked(android.content.ComponentName, android.content.Intent, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3fb8f0a..18e2a95 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2051,6 +2051,68 @@
     }
 
     /**
+     * Called by device or profile owner to block or unblock packages. When a package is blocked it
+     * is unavailable for use, but the data and actual package file remain.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The name of the package to block or unblock.
+     * @param blocked {@code true} if the package should be blocked, {@code false} if it should be
+     *                 unblocked.
+     * @return boolean Whether the blocked setting of the package was successfully updated.
+     */
+    public boolean setApplicationBlocked(ComponentName admin, String packageName,
+            boolean blocked) {
+        if (mService != null) {
+            try {
+                return mService.setApplicationBlocked(admin, packageName, blocked);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by profile or device owner to block or unblock currently installed packages. This
+     * should only be called by a profile or device owner running within a managed profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param intent An intent matching the app(s) to be updated. All apps that resolve for this
+     *               intent will be updated in the current profile.
+     * @param blocked {@code true} if the packages should be blocked, {@code false} if they should
+     *                 be unblocked.
+     * @return int The number of activities that matched the intent and were updated.
+     */
+    public int setApplicationsBlocked(ComponentName admin, Intent intent, boolean blocked) {
+        if (mService != null) {
+            try {
+                return mService.setApplicationsBlocked(admin, intent, blocked);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Called by device or profile owner to determine if a package is blocked.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The name of the package to retrieve the blocked status of.
+     * @return boolean {@code true} if the package is blocked, {@code false} otherwise.
+     */
+    public boolean isApplicationBlocked(ComponentName admin, String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isApplicationBlocked(admin, packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by profile or device owner to re-enable a system app that was disabled by default
      * when the managed profile was created. This should only be called from a profile or device
      * owner running within a managed profile.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 28588f1..7257158 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -124,6 +124,10 @@
     void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearForwardingIntentFilters(in ComponentName admin);
 
+    boolean setApplicationBlocked(in ComponentName admin, in String packageName, boolean blocked);
+    int setApplicationsBlocked(in ComponentName admin, in Intent intent, boolean blocked);
+    boolean isApplicationBlocked(in ComponentName admin, in String packageName);
+
     void enableSystemApp(in ComponentName admin, in String packageName);
     int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 773ccb3..bc7742f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3384,6 +3384,93 @@
     }
 
     @Override
+    public boolean setApplicationBlocked(ComponentName who, String packageName,
+            boolean blocked) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                return pm.setApplicationBlockedSettingAsUser(packageName, blocked, callingUserId);
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to setApplicationBlockedSetting", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public int setApplicationsBlocked(ComponentName who, Intent intent, boolean blocked) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                        PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_UNINSTALLED_PACKAGES,
+                        callingUserId);
+
+                if (DBG) Slog.d(LOG_TAG, "Enabling activities: " + activitiesToEnable);
+                int numberOfAppsUnblocked = 0;
+                if (activitiesToEnable != null) {
+                    for (ResolveInfo info : activitiesToEnable) {
+                        if (info.activityInfo != null) {
+                            numberOfAppsUnblocked++;
+                            pm.setApplicationBlockedSettingAsUser(info.activityInfo.packageName,
+                                    blocked, callingUserId);
+                        }
+                    }
+                }
+                return numberOfAppsUnblocked;
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to setApplicationsBlockedSettingsWithIntent", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return 0;
+        }
+    }
+
+    @Override
+    public boolean isApplicationBlocked(ComponentName who, String packageName) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                return pm.getApplicationBlockedSettingAsUser(packageName, callingUserId);
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.e(LOG_TAG, "Failed to getApplicationBlockedSettingAsUser", re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return false;
+        }
+    }
+
+    @Override
     public void enableSystemApp(ComponentName who, String packageName) {
         synchronized (this) {
             if (who == null) {