Merge "Restrict visibility of LOCUS_ID_SET events."
diff --git a/api/system-current.txt b/api/system-current.txt
index 59cc616..b3a2c13 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9,6 +9,7 @@
     field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
     field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
     field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
+    field public static final String ACCESS_LOCUS_ID_USAGE_STATS = "android.permission.ACCESS_LOCUS_ID_USAGE_STATS";
     field public static final String ACCESS_MESSAGES_ON_ICC = "android.permission.ACCESS_MESSAGES_ON_ICC";
     field public static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
     field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d1031f4..57ba7fe 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4943,6 +4943,10 @@
     <permission android:name="android.permission.ACCESS_TV_TUNER"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
+    <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
+                android:protectionLevel="signature|appPredictor" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 772f6e4..cc2c92b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -253,6 +253,9 @@
     <!-- Permission required for CTS test - ShortcutManagerUsageTest -->
     <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
 
+     <!-- Permission required for CTS test - UsageStatsTest -->
+    <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
+
     <!-- Permissions required to test ambient display. -->
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 5c2cbfa..442c9e5 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -220,9 +220,13 @@
      *     result.
      * @param hideShortcutInvocationEvents whether the {@link UsageEvents.Event#SHORTCUT_INVOCATION}
      *     events need to be excluded from the result.
+     * @param hideLocusIdEvents whether the {@link UsageEvents.Event#LOCUS_ID_SET}
+     *     events need to be excluded from the result.
+     *
      */
     public abstract UsageEvents queryEventsForUser(@UserIdInt int userId, long beginTime,
-            long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents);
+            long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents,
+            boolean hideLocusIdEvents);
 
     /**
      * Used to persist the last time a job was run for this app, in order to make decisions later
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
index 4e37f47..644c155 100644
--- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -59,7 +59,7 @@
      */
     boolean querySince(long sinceTime) {
         UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
-                mUserId, sinceTime, System.currentTimeMillis(), false, false);
+                mUserId, sinceTime, System.currentTimeMillis(), false, false, false);
         if (usageEvents == null) {
             return false;
         }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index b273578..01d9dc0 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -189,7 +189,7 @@
     private void addUsageEvents(UsageEvents.Event... events) {
         UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
         when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
-                anyBoolean(), anyBoolean())).thenReturn(usageEvents);
+                anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(usageEvents);
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1371481..420695d 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -491,6 +491,15 @@
         return true; // hide by default if we can't verify visibility
     }
 
+    private boolean shouldHideLocusIdEvents(int callingPid, int callingUid) {
+        if (callingUid == Process.SYSTEM_UID) {
+            return false;
+        }
+        return !(getContext().checkPermission(
+                android.Manifest.permission.ACCESS_LOCUS_ID_USAGE_STATS, callingPid, callingUid)
+                == PackageManager.PERMISSION_GRANTED);
+    }
+
     private static void deleteRecursively(File f) {
         File[] files = f.listFiles();
         if (files != null) {
@@ -1030,7 +1039,8 @@
      * Called by the Binder stub.
      */
     UsageEvents queryEvents(int userId, long beginTime, long endTime,
-            boolean shouldObfuscateInstantApps, boolean shouldHideShortcutInvocationEvents) {
+            boolean shouldObfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
+            boolean shouldHideLocusIdEvents) {
         synchronized (mLock) {
             if (!mUserUnlockedStates.get(userId)) {
                 Slog.w(TAG, "Failed to query events for locked user " + userId);
@@ -1042,7 +1052,7 @@
                 return null; // user was stopped or removed
             }
             return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps,
-                    shouldHideShortcutInvocationEvents);
+                    shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
         }
     }
 
@@ -1465,8 +1475,10 @@
             try {
                 final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
                         userId, callingPackage, callingPid, callingUid);
+                boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
                 return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
-                        obfuscateInstantApps, hideShortcutInvocationEvents);
+                        obfuscateInstantApps, hideShortcutInvocationEvents,
+                        shouldHideLocusIdEvents);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1513,8 +1525,10 @@
             try {
                 final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
                         userId, callingPackage, callingPid, callingUid);
+                boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
                 return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
-                        obfuscateInstantApps, hideShortcutInvocationEvents);
+                        obfuscateInstantApps, hideShortcutInvocationEvents,
+                        shouldHideLocusIdEvents);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -2131,9 +2145,11 @@
 
         @Override
         public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime,
-                boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents) {
+                boolean obfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
+                boolean shouldHideLocusIdEvents) {
             return UsageStatsService.this.queryEvents(
-                    userId, beginTime, endTime, obfuscateInstantApps, hideShortcutInvocationEvents);
+                    userId, beginTime, endTime, obfuscateInstantApps,
+                    shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
         }
 
         @Override
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 4d71112..d9317ac 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -481,8 +481,8 @@
         return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
     }
 
-    UsageEvents queryEvents(final long beginTime, final long endTime,
-                            boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents) {
+    UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps,
+            boolean hideShortcutInvocationEvents, boolean hideLocusIdEvents) {
         if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
             return null;
         }
@@ -504,6 +504,10 @@
                                     && event.mEventType == Event.SHORTCUT_INVOCATION) {
                                 continue;
                             }
+                            if (hideLocusIdEvents
+                                    && event.mEventType == Event.LOCUS_ID_SET) {
+                                continue;
+                            }
                             if (obfuscateInstantApps) {
                                 event = event.getObfuscatedIfInstantApp();
                             }