Skip grant dialog when permission are granted

This is a 1:1 resubmission of I4a7baa8f8d2bb62f8a6e8fa601039056757261e1.
The fixes will be submitted on top of that.

Test: Granted verious permissions sets via UI while also granting some of the
      permissions via the shell

Change-Id: Idd87afe78af5abf63b9a361a2dce4c99052b3e4d
diff --git a/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index a8096c2..9d95e55 100644
--- a/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -33,6 +33,7 @@
 import android.os.Bundle;
 import android.text.Html;
 import android.text.Spanned;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -72,6 +73,13 @@
 
     boolean mResultSet;
 
+    private PackageManager.OnPermissionsChangedListener mPermissionChangeListener;
+
+    private int getPermissionPolicy() {
+        DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
+        return devicePolicyManager.getPermissionPolicy(null);
+    }
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -112,6 +120,13 @@
             return;
         }
 
+        try {
+            mPermissionChangeListener = new PermissionChangeListener();
+        } catch (NameNotFoundException e) {
+            setResultAndFinish();
+            return;
+        }
+
         PackageInfo callingPackageInfo = getCallingPackageInfo();
 
         if (callingPackageInfo == null || callingPackageInfo.requestedPermissions == null
@@ -129,11 +144,7 @@
             return;
         }
 
-        DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
-        final int permissionPolicy = devicePolicyManager.getPermissionPolicy(null);
-
-        // If calling package is null we default to deny all.
-        updateDefaultResults(callingPackageInfo, permissionPolicy);
+        updateAlreadyGrantedPermissions(getCallingPackageInfo(), getPermissionPolicy());
 
         mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false,
                 new Runnable() {
@@ -161,7 +172,7 @@
             // We allow the user to choose only non-fixed permissions. A permission
             // is fixed either by device policy or the user denying with prejudice.
             if (!group.isUserFixed() && !group.isPolicyFixed()) {
-                switch (permissionPolicy) {
+                switch (getPermissionPolicy()) {
                     case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: {
                         if (!group.areRuntimePermissionsGranted()) {
                             group.grantRuntimePermissions(false, computeAffectedPermissions(
@@ -227,6 +238,78 @@
         }
     }
 
+
+    /**
+     * Update the {@link #mRequestedPermissions} if the system reports them as granted.
+     *
+     * <p>This also updates the {@link #mAppPermissions} state and switches to the next group grant
+     * request if the current group becomes granted.
+     */
+    private void updateIfPermissionsWereGranted() {
+        updateAlreadyGrantedPermissions(getCallingPackageInfo(), getPermissionPolicy());
+
+        ArraySet<String> grantedPermissionNames = new ArraySet<>(mRequestedPermissions.length);
+        for (int i = 0; i < mRequestedPermissions.length; i++) {
+            if (mGrantResults[i] == PERMISSION_GRANTED) {
+                grantedPermissionNames.add(mRequestedPermissions[i]);
+            }
+        }
+
+        boolean mightShowNextGroup = true;
+        int numGroups = mAppPermissions.getPermissionGroups().size();
+        for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+            AppPermissionGroup group = mAppPermissions.getPermissionGroups().get(groupNum);
+            GroupState groupState = mRequestGrantPermissionGroups.get(group.getName());
+
+            if (groupState == null || groupState.mState != GroupState.STATE_UNKNOWN) {
+                // Group has already been approved / denied via the UI by the user
+                continue;
+            }
+
+            boolean allAffectedPermissionsOfThisGroupAreGranted = true;
+
+            for (int permNum = 0; permNum < groupState.affectedPermissions.length;
+                    permNum++) {
+                if (!grantedPermissionNames.contains(
+                        groupState.affectedPermissions[permNum])) {
+                    allAffectedPermissionsOfThisGroupAreGranted = false;
+                    break;
+                }
+            }
+
+            if (allAffectedPermissionsOfThisGroupAreGranted) {
+                groupState.mState = GroupState.STATE_ALLOWED;
+
+                if (mightShowNextGroup) {
+                    // The UI currently displays the first group with
+                    // mState == STATE_UNKNOWN. So we are switching to next group until we
+                    // could not allow a group that was still unknown
+                    if (!showNextPermissionGroupGrantRequest()) {
+                        setResultAndFinish();
+                    }
+                }
+            } else {
+                mightShowNextGroup = false;
+            }
+        }
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        getPackageManager().addOnPermissionsChangeListener(mPermissionChangeListener);
+
+        updateIfPermissionsWereGranted();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        getPackageManager().removeOnPermissionsChangeListener(mPermissionChangeListener);
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -435,13 +518,16 @@
         }
     }
 
-    private void updateDefaultResults(PackageInfo callingPackageInfo, int permissionPolicy) {
+    private void updateAlreadyGrantedPermissions(PackageInfo callingPackageInfo,
+            int permissionPolicy) {
         final int requestedPermCount = mRequestedPermissions.length;
         for (int i = 0; i < requestedPermCount; i++) {
             String permission = mRequestedPermissions[i];
-            mGrantResults[i] = callingPackageInfo != null
-                    ? computePermissionGrantState(callingPackageInfo, permission, permissionPolicy)
-                    : PERMISSION_DENIED;
+
+            if (computePermissionGrantState(callingPackageInfo, permission, permissionPolicy)
+                    == PERMISSION_GRANTED) {
+                mGrantResults[i] = PERMISSION_GRANTED;
+            }
         }
     }
 
@@ -513,4 +599,19 @@
             mGroup = group;
         }
     }
+
+    private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener {
+        final int mCallingPackageUid;
+
+        PermissionChangeListener() throws NameNotFoundException {
+            mCallingPackageUid = getPackageManager().getPackageUid(getCallingPackage(), 0);
+        }
+
+        @Override
+        public void onPermissionsChanged(int uid) {
+            if (uid == mCallingPackageUid) {
+                updateIfPermissionsWereGranted();
+            }
+        }
+    }
 }