Add new location monitoring op, make some of app ops public.

The new location monitoring op is to tell us when an application
is monitoring for any location changes.  It may be useful information
in addition to the more explicitly information about when location
data actually goes to the app.

Also make parts of AppOpsManager public for use by gcore.  It is
not available to third party apps.

Change-Id: Ib639f704258ffdd7f3acd7567350ed2539da628a
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 231cfe1..c6c9845 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -47,7 +47,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -222,6 +221,9 @@
             AppOpsManager.Callback callback = new AppOpsManager.Callback() {
                 public void opChanged(int op, String packageName) {
                     synchronized (mLock) {
+                        for (Receiver receiver : mReceivers.values()) {
+                            receiver.updateMonitoring(true);
+                        }
                         applyAllProviderRequirementsLocked();
                     }
                 }
@@ -460,6 +462,7 @@
 
         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
 
+        boolean mOpMonitoring;
         int mPendingBroadcasts;
         PowerManager.WakeLock mWakeLock;
 
@@ -477,6 +480,8 @@
             mPid = pid;
             mPackageName = packageName;
 
+            updateMonitoring(true);
+
             // construct/configure wakelock
             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
             mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
@@ -512,6 +517,21 @@
             return s.toString();
         }
 
+        public void updateMonitoring(boolean allow) {
+            if (!mOpMonitoring) {
+                if (allow) {
+                    mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
+                            mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
+                }
+            } else {
+                if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
+                        mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
+                    mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
+                    mOpMonitoring = false;
+                }
+            }
+        }
+
         public boolean isListener() {
             return mListener != null;
         }
@@ -1366,6 +1386,8 @@
             }
         }
 
+        receiver.updateMonitoring(false);
+
         // Record which providers were associated with this listener
         HashSet<String> providers = new HashSet<String>();
         HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;