resolved conflicts for merge of c8911ddd to master

Change-Id: I790b547268a23848577199256fc5abc9bdb7abb8
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0f988ed..fe09ce1 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -527,6 +527,14 @@
         }
     }
 
+    /** @hide */
+    public void resetAllModes() {
+        try {
+            mService.resetAllModes();
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Monitor for changes to the operating mode for the given op in the given app package.
      * @param op The operation to monitor, one of OP_*.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2dc822e..b798a1a 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -34,4 +34,5 @@
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
     void setMode(int code, int uid, String packageName, int mode);
+    void resetAllModes();
 }
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 6b4d248..81572c5 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -27,6 +27,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -43,6 +44,7 @@
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -334,6 +336,24 @@
         }
     }
 
+    private void pruneOp(Op op, int uid, String packageName) {
+        if (op.time == 0 && op.rejectTime == 0) {
+            Ops ops = getOpsLocked(uid, packageName, false);
+            if (ops != null) {
+                ops.remove(op.op);
+                if (ops.size() <= 0) {
+                    HashMap<String, Ops> pkgOps = mUidOps.get(uid);
+                    if (pkgOps != null) {
+                        pkgOps.remove(ops.packageName);
+                        if (pkgOps.size() <= 0) {
+                            mUidOps.remove(uid);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void setMode(int code, int uid, String packageName, int mode) {
         verifyIncomingUid(uid);
@@ -362,21 +382,7 @@
                     if (mode == AppOpsManager.MODE_ALLOWED) {
                         // If going into the default mode, prune this op
                         // if there is nothing else interesting in it.
-                        if (op.time == 0 && op.rejectTime == 0) {
-                            Ops ops = getOpsLocked(uid, packageName, false);
-                            if (ops != null) {
-                                ops.remove(op.op);
-                                if (ops.size() <= 0) {
-                                    HashMap<String, Ops> pkgOps = mUidOps.get(uid);
-                                    if (pkgOps != null) {
-                                        pkgOps.remove(ops.packageName);
-                                        if (pkgOps.size() <= 0) {
-                                            mUidOps.remove(uid);
-                                        }
-                                    }
-                                }
-                            }
-                        }
+                        pruneOp(op, uid, packageName);
                     }
                     scheduleWriteNowLocked();
                 }
@@ -392,6 +398,72 @@
         }
     }
 
+    private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks(
+            HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks,
+            String packageName, int op, ArrayList<Callback> cbs) {
+        if (cbs == null) {
+            return callbacks;
+        }
+        if (callbacks == null) {
+            callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>();
+        }
+        for (int i=0; i<cbs.size(); i++) {
+            Callback cb = cbs.get(i);
+            ArrayList<Pair<String, Integer>> reports = callbacks.get(cb);
+            if (reports == null) {
+                reports = new ArrayList<Pair<String, Integer>>();
+                callbacks.put(cb, reports);
+            }
+            reports.add(new Pair<String, Integer>(packageName, op));
+        }
+        return callbacks;
+    }
+
+    @Override
+    public void resetAllModes() {
+        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
+        synchronized (this) {
+            boolean changed = false;
+            for (int i=0; i<mUidOps.size(); i++) {
+                HashMap<String, Ops> packages = mUidOps.valueAt(i);
+                for (Map.Entry<String, Ops> ent : packages.entrySet()) {
+                    String packageName = ent.getKey();
+                    Ops pkgOps = ent.getValue();
+                    for (int j=0; j<pkgOps.size(); j++) {
+                        Op curOp = pkgOps.valueAt(j);
+                        if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
+                            curOp.mode = AppOpsManager.MODE_ALLOWED;
+                            changed = true;
+                            callbacks = addCallbacks(callbacks, packageName, curOp.op,
+                                    mOpModeWatchers.get(curOp.op));
+                            callbacks = addCallbacks(callbacks, packageName, curOp.op,
+                                    mPackageModeWatchers.get(packageName));
+                            pruneOp(curOp, mUidOps.keyAt(i), packageName);
+                        }
+                    }
+                }
+            }
+            if (changed) {
+                scheduleWriteNowLocked();
+            }
+        }
+        if (callbacks != null) {
+            for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) {
+                Callback cb = ent.getKey();
+                ArrayList<Pair<String, Integer>> reports = ent.getValue();
+                for (int i=0; i<reports.size(); i++) {
+                    Pair<String, Integer> rep = reports.get(i);
+                    try {
+                        cb.mCallback.opChanged(rep.second, rep.first);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
         synchronized (this) {